Skip to content

Stripe Invoices: Automated Billing and Payment Collection

DodaTech Updated 2026-06-28 5 min read

In this tutorial, you will learn about Stripe Invoices: Automated Billing and Payment Collection. We cover key concepts, practical examples, and best practices to help you master this topic.

Stripe Invoices represent a request for payment, automatically generated for subscriptions, supporting one-time charges, payment retries, discounts, tax calculation, and hosted invoice pages.

What You'll Learn

How invoices are generated for subscriptions, how to create one-time invoices, manage auto-advance and collection, configure payment retry logic, add discounts and tax, and use the hosted invoice page.

Why It Matters

Automated invoicing ensures reliable revenue collection, reduces payment failures through smart retries, and provides professional billing documents. DodaTech processes thousands of subscription invoices monthly through Stripe's automated billing engine.

Real-World Use

A Pro customer's subscription renews. Stripe generates an invoice, sends it via email, attempts payment with the saved card, retries on failure, and marks it paid or finalizes after dunning.

flowchart LR
    A["Subscription\nRenewal Date"] --> B["Generate\nInvoice"]
    B --> C["Auto-Advance\n= True"]
    C --> D["Attempt\nPayment"]
    D --> E{"Payment\nResult"}
    E -->|Success| F["Invoice\nPaid"]
    E -->|Failure| G["Retry\n(4 attempts)"]
    G --> H{"All\nFailed"}
    H -->|Yes| I["Invoice\nUncollectible"]
    H -->|No| D
    style A fill:#6772e5,color:#fff
    style D fill:#dbeafe,stroke:#2563eb
    style F fill:#bbf7d0,stroke:#16a34a
    style I fill:#fecaca,stroke:#dc2626

Viewing and Finalizing Invoices

import stripe
stripe.api_key = "sk_test_..."

# Retrieve invoices for a subscription
subscription_id = "sub_ProABC123"
invoices = stripe.Invoice.list(subscription=subscription_id, limit=5)
for inv in invoices:
    print(f"Invoice: {inv.id}")
    print(f"  Amount Due: ${inv.amount_due/100:.2f}")
    print(f"  Amount Paid: ${inv.amount_paid/100:.2f}")
    print(f"  Status: {inv.status}")
    print(f"  Created: {inv.created}")
    print()

# Expected output:
# Invoice: in_1JanInvoiceABC
#   Amount Due: $29.99
#   Amount Paid: $29.99
#   Status: paid
#   Created: 1719561600

# Finalize a draft invoice
def finalize_invoice(invoice_id):
    invoice = stripe.Invoice.finalize_invoice(invoice_id)
    print(f"Finalized: {invoice.id}")
    print(f"Status: {invoice.status}")
    print(f"Hosted URL: {invoice.hosted_invoice_url}")
    return invoice

# Invoice: in_1DraftInvoiceXYZ
# Finalized: in_1DraftInvoiceXYZ
# Status: open
# Hosted URL: https://invoice.stripe.com/i/acct_...

One-Time Invoices

def create_one_time_invoice(customer_id, items, days_until_due=30):
    # Create invoice items first
    for item in items:
        stripe.InvoiceItem.create(
            customer=customer_id,
            amount=item["amount"],
            currency=item.get("currency", "usd"),
            description=item["description"],
            quantity=item.get("quantity", 1)
        )
    invoice = stripe.Invoice.create(
        customer=customer_id,
        collection_method="send_invoice",
        days_until_due=days_until_due
    )
    invoice = stripe.Invoice.finalize_invoice(invoice.id)
    print(f"Invoice: {invoice.id}")
    print(f"Amount Due: ${invoice.amount_due/100:.2f}")
    print(f"Payment URL: {invoice.hosted_invoice_url}")
    return invoice

# Usage
items = [
    {"amount": 5000, "description": "Consulting Hourly", "quantity": 10},
    {"amount": 2000, "description": "Setup Fee", "quantity": 1}
]
# cus_CustomerXYZ is an existing customer
inv = create_one_time_invoice("cus_CustomerXYZ", items)
# Expected output:
# Invoice: in_1OneTimeABC
# Amount Due: $520.00
# Payment URL: https://invoice.stripe.com/i/acct_...

Payment Retries and Dunning

# Configure payment settings for automatic retries
def configure_payment_settings(customer_id, payment_method_id):
    # Set default payment method
    stripe.Customer.update(
        customer_id,
        invoice_settings={
            "default_payment_method": payment_method_id
        }
    )

    # Stripe automatically retries failed invoices
    # Default: 4 retries over ~30 days
    # You can customize retry behavior via Dashboard
    print(f"Default retry configured for {customer_id}")

# Manually trigger a payment attempt
def retry_invoice_payment(invoice_id):
    invoice = stripe.Invoice.pay(invoice_id)
    print(f"Retry result: {invoice.id} ({invoice.status})")
    if invoice.status == "paid":
        print("Payment succeeded on retry")
    else:
        print(f"Still failed. Last error: {invoice.last_finalization_error}")
    return invoice

# Expected output:
# Retry result: in_1FailedRetryABC (paid)
# Payment succeeded on retry

Common Mistakes

1. Not Handling auto_advance Correctly

If auto_advance is false, the invoice stays as draft forever. It won't be finalized or sent. Set auto_advance: true for automatic processing.

2. Forgetting to Finalize Draft Invoices

Draft invoices do not attempt payment. You must call finalize_invoice to transition from draft to open, which triggers payment collection.

3. Using send_invoice Without days_until_due

When collection_method: send_invoice, you must set days_until_due. Without it, Stripe defaults to 0, making it due immediately and potentially causing failed collection.

4. Ignoring Failed Payment Retries

Stripe retries failed payments up to 4 times. Monitor payment_intent.status on invoices. If all retries fail, the invoice becomes uncollectible. Notify customers before the final attempt.

5. Creating Duplicate Line Items

Calling InvoiceItem.create multiple times creates separate line items. If you want a single line with quantity, pass quantity in the invoice item rather than creating duplicates.

Practice Questions

  1. What is the lifecycle of a subscription invoice?
  2. How do you create a one-time invoice for a custom amount?
  3. What happens when an invoice payment fails?
  4. How do customers pay a send_invoice type invoice?

Answers:

  1. draft -> open (after finalize) -> paid or uncollectible or void. Subscriptions auto-generate invoices at renewal, which auto-advance through the lifecycle.
  2. Create InvoiceItems for each line with InvoiceItem.create, then create an Invoice with collection_method: send_invoice, then call finalize_invoice.
  3. Stripe automatically retries up to 4 times over ~30 days. You can also manually retry via API. After all retries fail, the invoice becomes uncollectible.
  4. Customers receive an email with a link to Stripe's hosted invoice page where they can pay by card or bank transfer. The URL is available via invoice.hosted_invoice_url.

Challenge: Build an invoicing system: create a subscription for a customer, let it generate an invoice, retrieve and display invoice details, simulate a payment failure by using a failing test card (4000000000000002), configure automatic retry, then manually trigger payment after updating the card to a valid test card.

FAQ

Can I send invoices via email automatically?

Yes, Stripe sends invoice emails automatically when the invoice is finalized. You can customize the email template in the Dashboard under Branding > Email.

How do I add tax to invoices?

Use Stripe Tax for automatic tax calculation, or manually add tax line items. For automatic tax, enable Stripe Tax and set automatic_tax: { enabled: true } on the invoice.

What is a credit note?

A credit note reduces the amount owed or refunds an overpayment. It is linked to an invoice and appears as a negative amount on the customer's next invoice.

Can I preview an invoice before finalizing?

Yes, use stripe.Invoice.create_preview to see what the upcoming invoice would look like without creating it. This is useful for showing upcoming charges.

How do void vs uncollectible differ?

Void cancels the invoice entirely — the customer never pays. Uncollectible marks it as bad debt — you tried but couldn't collect. Both close the invoice, but uncollectible is used for accounting purposes.

Mini Project

Build an invoice management system: create a subscription, retrieve the generated invoice, add a one-time credit note via InvoiceItem, finalize, attempt payment with a failing card, observe the dunning cycle, update the payment method, retry successfully, and verify the paid invoice status.

What's Next

Testing Stripe — simulate various payment scenarios using test cards.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro