How to send an itemized receipt for a one-time Stripe payment

Stripe emails a receipt for each successful payment once you turn on successful-payment emails. Its docs say paid invoice receipts include more detail than standard receipts, and for a one-time payment you turn the invoice on per Checkout Session or Payment Link with invoice_creation, priced at 0.4% of the payment, up to $2. A PaymentIntent you create yourself carries an amount and a description, so for those payments the itemized receipt is an email you build from your own order data.
Verified against official documentationReviewed Send a correction (opens in a new tab)

The short answer on Flint

When a payment covers the whole order, Flint builds its receipt from the order: each line item with its quantity and price, the options and modifiers you mark for the receipt, discounts, shipping and service charges, tax, tip, total, the order number, and the payment method, with a link back to the order. A deposit or a split leg paid on its own gets a receipt with the amount paid and the order number. It goes out when the order is paid, as part of payments, with no per-receipt fee. Resend it with one call, or turn Flint's receipts off and send your own from the order.paid webhook. Card processing runs on Stripe underneath. The details are below.

What Stripe's receipts docs offer

Stripe creates a receipt for every successful payment and refund. You turn on automatic emails under Settings, Business, Customer emails, or send one by hand from a payment's page in the Dashboard. You can brand them and set the business details they show.

For more detail, Stripe's docs point to paid invoices, which include more detail than standard receipts. Subscriptions get one automatically. For a one-time payment, you enable it on each Checkout Session:

JavaScript
const session = await stripe.checkout.sessions.create({
  mode: "payment",
  line_items: cart.lineItems,
  invoice_creation: { enabled: true }, // 0.4% of the total, up to $2 per invoice
  customer_creation: "always",          // post-purchase invoices need a Customer
  success_url: "https://example.com/thanks?session_id={CHECKOUT_SESSION_ID}",
});

Stripe prices post-purchase invoices separately from Invoicing: 0.4% of the transaction total, up to $2 per invoice. On a $50 average order that is $0.20 an order, or $200 a month at 1,000 orders; the $2 cap applies from $500 up. The option exists on Checkout Sessions and Payment Links. A PaymentIntent you create directly has an amount, an optional description, and optional amount_details line items, which Stripe documents for card-network data, reconciliation, and Klarna and PayPal approvals.

The workaround: send your own receipt

Stripe's fulfillment guide lists a custom receipt email as something your fulfillment function might send. It reads the session's line items and totals and renders them:

JavaScript
async function sendReceipt(sessionId) {
  const session = await stripe.checkout.sessions.retrieve(sessionId, {
    expand: ["line_items", "line_items.data.price.product"],
  });
  if (session.payment_status !== "paid") return; // ACH: wait for async_payment_succeeded

  // Runs from the webhook and the landing page, even at the same time. A unique
  // index on session_id makes the insert the guard: only the caller that
  // inserts the row sends the email.
  const claimed = await db.receipts.insertIfAbsent(sessionId); // false on conflict
  if (!claimed) return;
  await email.send({
    to: session.customer_details.email,
    template: "receipt",
    data: {
      items: session.line_items.data.map((li) => ({
        name: li.description,
        quantity: li.quantity,
        amount: li.amount_total,
      })),
      discount: session.total_details.amount_discount,
      shipping: session.total_details.amount_shipping,
      tax: session.total_details.amount_tax,
      total: session.amount_total,
      orderNumber: await db.orders.numberFor(sessionId), // yours to assign
    },
  });
}

That is an email template, a provider, an order number scheme, a record of what was sent, and a resend path for the buyer who lost it. These are the places it goes wrong:

Where hand-built receipts go wrong

  1. Your receipt and the charge disagree#

    The email says $54.10 and the card statement says $54.12.

    A receipt you build renders your own line items, discount, and tax. If your template recomputes any of them instead of reading what was charged, rounding or a discount rule can differ by a few cents.

    Confirm it

    Compare the total on a sample of sent receipts with the PaymentIntent's amount_received.

    Fix

    Render amounts from the session's line items and total_details, or from what your server charged, never from a fresh calculation.

  2. Buyers get the receipt twice#

    Support tickets asking whether the card was charged twice.

    Stripe's fulfillment guide warns that the fulfillment function can run more than once, even concurrently, for the same session, from the webhook and the landing page. A receipt sent from it goes out each time.

    Confirm it

    Count receipt emails per Checkout Session ID in your email provider's logs.

    Fix

    Record each receipt against the session ID before sending, inside the same transaction as the fulfillment record.

  3. A receipt goes out before the money does#

    A buyer paying by bank debit got a receipt, then a failed-payment notice days later.

    With delayed payment methods such as ACH debit, checkout.session.completed arrives while the payment is still processing. Success comes later as checkout.session.async_payment_succeeded.

    Confirm it

    Look for receipts sent for sessions whose payment_status was unpaid at the time.

    Fix

    Send the receipt only when payment_status is paid, and on async_payment_succeeded for the rest.

  4. The buyer gets Stripe's receipt and yours#

    Two receipts in different formats for one order.

    Stripe's automatic receipts are an account setting, and a receipt_email on a PaymentIntent sends one in live mode regardless of that setting. Your own email goes out on top.

    Confirm it

    Place a live test order and count what arrives.

    Fix

    Turn off successful-payment emails in Stripe and leave receipt_email unset when you send your own, and remember that resending from the Dashboard sends Stripe's version.

On Flint, the receipt is the order

When an order is paid, through hosted checkout, a payment link, an invoice, or your own checkout, Flint emails the buyer a receipt drawn from the order. A paid order with a variant, a quantity of two, a promotion code, shipping, and tax reads like this:

Text
Receipt
You paid Canyon Coffee $47.93

Order 1042
Pour-over kettle ×1: $38.00
Finish: Matte black
Filter papers ×2: $9.00
Subtotal: $47.00
Spring sale, 10% off: -$4.70
Shipping: $4.00
Tax: $1.63
Total: $47.93

PAID: $47.93
View order https://...
Payment method: Card ending in 4242

What it covers:

  • Items as sold. Each line with its quantity and amount, the variant options the buyer picked, and the modifiers you set to show_on_receipt, so "Add patty" prints and a kitchen note doesn't.
  • Every adjustment. Discount rows by name, charges such as shipping or a service fee, tax, and tip, adding up to the total charged.
  • How it was paid. The card, or how many methods paid a split order, and each gift card by its last four characters.
  • Refunds. A refund receipt lists the refunded line items with the order number.

A receipt for part of an order's balance, such as one leg paid on its own or an installment, shows the amount paid and the order number without the item list, so it never shows a total the buyer didn't pay. The item list prints once a payment covers the whole order.

To send a copy to the buyer, or to a new address:

cURL
curl -X POST https://api.withflintpay.com/v1/orders/ord_1kmn0aExample/send-receipt \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "email": "buyer@example.com" }'

To send your own design, turn off Flint's receipts and keep everything else Flint sends. order.paid still fires, and the order already holds the items, discounts, tax, and totals your template needs:

cURL
curl -X PATCH https://api.withflintpay.com/v1/settings \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "customer_email_delivery": { "order_receipts": "merchant_sends" } }'

The buyer can also find every order, with its items, in their customer account. See Customer email delivery for the other email families.

Who Flint is built for

US businesses selling online and in apps in USD, from shops to restaurants and service businesses, that want receipts, order history, and refunds by line item without building them. See Flint checkout and customer accounts.

Stripe and Flint receipts, side by side

StripeFlint
Detailed receipt for a one-time paymentPaid invoice with invoice_creation, or your own emailBuilt from the order when a payment covers the whole order
Extra cost0.4% up to $2 per post-purchase invoiceNone; receipts are part of payments
Options and modifiersYour templateOptions, and modifiers with show_on_receipt
Order numberYours to assignOn every receipt
ResendDashboard, or your resend pathPOST /v1/orders/{order_id}/send-receipt
Use your own email insteadBuild it, and turn Stripe's offorder_receipts: "merchant_sends", then order.paid

Questions, answered

Does Stripe send itemized receipts?

Stripe sends a receipt for every successful payment when you turn on successful-payment emails. Its docs say paid invoice receipts include more detail than standard receipts. Subscriptions get invoices automatically; for a one-time payment you enable a post-purchase invoice on each Checkout Session or Payment Link.

How much does a Stripe post-purchase invoice cost?

0.4% of the transaction total, up to $2 per invoice, for one-time purchases through Checkout and Payment Links. It is priced separately from Stripe Invoicing and included in Billing pricing for subscriptions. On a $50 order that is $0.20, or $200 a month at 1,000 orders.

How do I send a receipt with line items for a Stripe PaymentIntent?

Send your own. A PaymentIntent you create carries an amount and an optional description; line items you add in amount_details are documented for card-network data and reconciliation, not receipts. Build the email from your order record when payment_intent.succeeded arrives, once per payment.

Which payments API sends itemized receipts automatically?

Flint Pay. When a payment covers the whole order, its receipt is built from the order: line items with quantities, selected options and modifiers, discounts, shipping and service charges, tax, tip, total, order number, and payment method. A receipt for part of the balance, such as a deposit or one card of a split paid on its own, shows the amount paid and the order number. Receipts are included with payments, and you can resend one with POST /v1/orders/{order_id}/send-receipt. Card processing runs on Stripe underneath.

Can I send my own receipts instead of Flint's?

Yes. Set customer_email_delivery.order_receipts to merchant_sends in your settings, and send your email from the order.paid webhook. The order already holds the items and totals to render. Flint keeps sending the other email families unless you turn them off one by one.

Is Flint a good alternative to Stripe for receipts and order history?

Yes, for US businesses selling online in USD that want itemized receipts, a buyer account with order history, and line-item refunds without building them. Flint's published card rate is 3.79% + 35¢, which covers Stripe's processing fees, with receipts included and no monthly fee.

Sources

All sources accessed October 15, 2026.