6 min read

How to Set Up Invoicing in Stripe

Stripe's invoicing feature lets you create and send professional invoices directly from your account, with built-in payment collection and automatic email delivery. If you're billing recurring customers or handling one-off charges, you need invoicing dialed in so you're not chasing payment confirmations manually.

Configure Invoicing in Your Stripe Account

Before you create your first invoice, set up your account defaults so every invoice reflects your brand and payment terms.

Enable Invoicing and Set Defaults

In your Stripe Dashboard, navigate to Settings > Billing settings and scroll to Invoices. Upload your logo, enter your business name and tax ID, and set your invoice numbering prefix. Stripe auto-increments from there. Configure your default Due date behavior — choose a fixed number of days after invoice creation or a specific day of the month.

Customize Your Email and Payment Behavior

In Invoicing settings, customize the Invoice email template. Add a personal note, payment instructions, or link to terms of service. Enable Automatic collection if you want Stripe to attempt charging the customer's default payment method on the due date. You can also set a Custom email footer for branding consistency.

javascript
// Create an invoice with automatic collection enabled
const invoice = await stripe.invoices.create({
  customer: 'cus_LTbM1234567890',
  collection_method: 'charge_automatically',
  due_date: Math.floor(Date.now() / 1000) + (30 * 86400), // 30 days
  auto_advance: true, // Finalize immediately after creation
});
Set collection_method to 'charge_automatically' for recurring billing, or 'send_invoice' to email only.

Configure Tax and Currency Settings

Set your default currency and tax behavior in Settings > Tax. If you bill customers in multiple countries, add tax rates for each jurisdiction. Stripe applies these automatically when you create invoices, so you don't have to recalculate taxes per invoice.

Tip: Your email domain must be verified in Settings > Email before Stripe can send invoices. Use a branded email address like [email protected] instead of the default Stripe address.

Create and Customize Invoices Programmatically

Once defaults are set, create invoices via the Stripe API. You can build line items inline or attach existing Prices.

Create an Invoice with Inline Line Items

Use stripe.invoices.create() to generate a new invoice. Define line items with price_data to specify amount, currency, product name, and quantity. Stripe calculates subtotals and taxes automatically. Each amount is in cents, so $50 USD is 5000.

javascript
const invoice = await stripe.invoices.create({
  customer: 'cus_LTbM1234567890',
  collection_method: 'send_invoice',
  days_until_due: 30,
  line_items: [
    {
      price_data: {
        currency: 'usd',
        product_data: {
          name: 'Web Development Services',
        },
        unit_amount: 50000, // $500.00
      },
      quantity: 1,
    },
    {
      price_data: {
        currency: 'usd',
        product_data: {
          name: 'Hosting (Annual)',
        },
        unit_amount: 120000, // $1,200.00
      },
      quantity: 1,
    },
  ],
});

console.log(`Draft invoice created: ${invoice.id}`);

Attach Existing Stripe Prices

If you already have Prices set up in Stripe, reference them by ID in line_items. This keeps your pricing consistent across invoices and subscriptions, and avoids duplicating product data. Use the price field instead of price_data.

javascript
const invoice = await stripe.invoices.create({
  customer: 'cus_LTbM1234567890',
  collection_method: 'send_invoice',
  days_until_due: 30,
  line_items: [
    {
      price: 'price_1NZ5J9FVhkK4t1234', // Reference existing price
      quantity: 2,
    },
  ],
});

console.log(`Invoice created: ${invoice.id}`);

Add Metadata to Track Invoices

Include metadata to store custom fields — project ID, customer tier, internal reference numbers. You can query invoices by metadata later and match them with your billing system.

javascript
const invoice = await stripe.invoices.create({
  customer: 'cus_LTbM1234567890',
  metadata: {
    project_id: 'proj_12345',
    customer_tier: 'enterprise',
    internal_invoice_number: 'INV-2024-001',
  },
  line_items: [
    {
      price_data: {
        currency: 'usd',
        product_data: { name: 'Consulting' },
        unit_amount: 75000,
      },
      quantity: 1,
    },
  ],
});
Watch out: Always set collection_method explicitly. If you omit it, Stripe defaults to 'charge_automatically', which may trigger unexpected payment attempts.

Finalize, Send, and Track Invoices

Draft invoices can't be sent to customers. Finalize to lock the invoice number, then send it via Stripe's email system.

Finalize and Send an Invoice

Call stripe.invoices.finalize(invoiceId) to lock the invoice and assign an invoice number. Then call stripe.invoices.sendInvoice(invoiceId) to email it to the customer. The customer receives a secure link to view and pay the invoice. You can finalize and send in the same request or separately.

javascript
// Finalize the invoice (assigns invoice number, prevents edits)
const finalized = await stripe.invoices.finalize('in_1NZ5J9FVhkK4t1234');

// Send to customer
const sent = await stripe.invoices.sendInvoice('in_1NZ5J9FVhkK4t1234');

console.log(`Invoice ${sent.number} sent to ${sent.customer_email}`);

Send Reminders for Unpaid Invoices

Query unpaid invoices with stripe.invoices.list() and filter by status: 'open'. Check the due_date to identify overdue invoices, then resend with stripe.invoices.sendInvoice() as a reminder. Stripe doesn't auto-send reminders, so you'll trigger these from your app.

javascript
// Get unpaid invoices for a customer
const invoices = await stripe.invoices.list({
  customer: 'cus_LTbM1234567890',
  status: 'open',
  limit: 10,
});

// Resend as reminder for overdue invoices
const now = Math.floor(Date.now() / 1000);
for (const inv of invoices.data) {
  if (inv.due_date && now > inv.due_date) {
    await stripe.invoices.sendInvoice(inv.id);
    console.log(`Reminder sent for invoice ${inv.id}`);
  }
}

Track Payments with Webhooks

Listen for invoice.payment_succeeded and invoice.payment_failed webhook events to track payment status in real-time. If you have charge_automatically enabled, you'll know immediately when a payment attempt fails so you can follow up.

javascript
// Handle invoice payment webhooks
export const handleInvoiceWebhook = (event) => {
  const invoice = event.data.object;

  if (event.type === 'invoice.payment_succeeded') {
    console.log(`Payment received for invoice ${invoice.id}`);
    // Update your database: invoice status = paid
  } else if (event.type === 'invoice.payment_failed') {
    console.log(`Payment failed for invoice ${invoice.id}`);
    // Alert customer, attempt recovery, retry logic
  }
};
Tip: Register webhook events in Developers > Webhooks in your Stripe Dashboard. Test webhook delivery with the Stripe CLI before deploying: stripe listen --forward-to localhost:3000/webhook.

Common Pitfalls

  • Forgetting to finalize invoices before sending — draft invoices can't be sent and won't get an invoice number.
  • Not setting collection_method explicitly — Stripe defaults to automatic collection, which may trigger unexpected charges if you only want to email invoices.
  • Creating duplicate line items instead of reusing Prices — if you bill the same service repeatedly, create a Price once and reference it by ID to avoid data duplication.
  • Ignoring payment_failed webhooks — if automatic collection fails, you won't know unless you listen to webhook events and take action.

Wrapping Up

With invoicing configured, you can create, send, and track customer invoices programmatically from Stripe. Set defaults in the Dashboard, create invoices via API with line items or existing Prices, finalize and send them, and track payment status through webhooks. If you want to track this automatically across tools, Product Analyst can help.

Track these metrics automatically

Product Analyst connects to your stack and surfaces the insights that matter.

Try Product Analyst — Free