Published on January 14, 2025

Automating Invoice Generation and Sending with Stripe

Automating Invoice Generation and Sending with Stripe

In this blog post, we will explore how to automate the process of generating and sending invoices using Stripe’s API in TypeScript. This can be a helpful tool for businesses looking to automate their billing processes.

Setting Up Stripe

To begin, you need to have a Stripe account. If you don’t have one, you can sign up at stripe.com. After signing up, you will need to obtain your Stripe API keys from the Stripe Dashboard. These keys are essential for server-side operations. Make sure you have Node.js and npm installed on your computer. You will also need to install the Stripe Node.js SDK, which you can do by running the command npm install stripe in your terminal.

Initializing the Stripe SDK

The first step is to import the Stripe library and initialize it with your secret key. It’s a good practice to store your secret key in an environment variable instead of hardcoding it directly into your code. This keeps your key secure. Here’s how you can do it:

import Stripe from 'stripe';

const stripeSecretKey = process.env.STRIPE_SECRET_KEY;

if (!stripeSecretKey) {
  throw new Error('STRIPE_SECRET_KEY is not set in the environment.');
}

const stripe = new Stripe(stripeSecretKey, {
  apiVersion: '2024-12-18.acacia'
});

Creating a Customer

If you don’t already have a customer in Stripe, you might want to create one. This is useful for managing your users and their payment information. However, you can skip this step if you already have a customer ID.

async function createCustomer(name: string, email: string) {
  try {
    const customer = await stripe.customers.create({
      name: name,
      email: email
    });
    return customer;
  } catch (error) {
    console.error('Error creating customer:', error);
    throw error;
  }
}

Creating an Invoice Item

If you want to add specific line items to the invoice, such as a one-time charge, you can create invoice items. This step is optional and can be skipped if you are creating an invoice from a subscription.

async function createInvoiceItem(
  customerId: string,
  amount: number,
  currency: string,
  description: string
) {
  try {
    const invoiceItem = await stripe.invoiceItems.create({
      customer: customerId,
      amount: amount,
      currency: currency,
      description: description
    });
    return invoiceItem;
  } catch (error) {
    console.error('Error creating invoice item:', error);
    throw error;
  }
}

Creating the Invoice

Now, you can create a new invoice using the stripe.invoices.create method. You need to provide at least the customer ID. You can also specify other options like collection_method (which can be set to send_invoice or charge_automatically), metadata, and more.

async function createInvoice(customerId: string) {
  try {
    const invoice = await stripe.invoices.create({
      customer: customerId,
      collection_method: 'send_invoice',
      metadata: {
        order_id: '12345'
      }
    });
    return invoice;
  } catch (error) {
    console.error('Error creating invoice:', error);
    throw error;
  }
}

Finalizing the Invoice

If you want to finalize the invoice immediately, you can use the stripe.invoices.finalizeInvoice method. This step is necessary to send the invoice to the customer or attempt payment.

async function finalizeInvoice(invoiceId: string) {
  try {
    const invoice = await stripe.invoices.finalizeInvoice(invoiceId);
    return invoice;
  } catch (error) {
    console.error('Error finalizing invoice:', error);
    throw error;
  }
}

Sending the Invoice

If you want to send the invoice email to the customer, you can use the stripe.invoices.sendInvoice method. This is only applicable if the collection_method was set to send_invoice.

async function sendInvoice(invoiceId: string) {
  try {
    const invoice = await stripe.invoices.sendInvoice(invoiceId);
    return invoice;
  } catch (error) {
    console.error('Error sending invoice:', error);
    throw error;
  }
}

Paying the Invoice

If you want to attempt to pay the invoice immediately, you can use the stripe.invoices.pay method. This is only applicable if the collection_method was set to charge_automatically and the customer has a default payment method.

async function payInvoice(invoiceId: string) {
  try {
    const invoice = await stripe.invoices.pay(invoiceId);
    return invoice;
  } catch (error) {
    console.error('Error paying invoice:', error);
    throw error;
  }
}

Example Usage

Here’s an example of how you can use these functions to create and send an invoice:

async function main() {
  try {
    const customer = await createCustomer('John Doe', 'john.doe@example.com');
    console.log('Created customer:', customer.id);

    const invoiceItem = await createInvoiceItem(
      customer.id,
      1000,
      'usd',
      'Consultation fee'
    );
    console.log('Created invoice item:', invoiceItem.id);

    const invoice = await createInvoice(customer.id);
    console.log('Created invoice:', invoice.id);

    const finalizedInvoice = await finalizeInvoice(invoice.id);
    console.log('Finalized invoice:', finalizedInvoice.id);

    const sentInvoice = await sendInvoice(finalizedInvoice.id);
    console.log('Sent invoice:', sentInvoice.id);
  } catch (error) {
    console.error('An error occurred:', error);
  }
}

main();

Explanation

  • stripe.customers.create(...): This creates a new customer object in Stripe.
  • stripe.invoiceItems.create(...): This creates a new invoice item, which is a line item on the invoice.
  • stripe.invoices.create(...): This creates a draft invoice.
  • stripe.invoices.finalizeInvoice(...): This finalizes the invoice, making it ready to be paid or sent.
  • stripe.invoices.sendInvoice(...): This sends the invoice to the customer’s email address.
  • stripe.invoices.pay(...): This attempts to pay the invoice using the customer’s default payment method.
  • Error Handling: The code includes try...catch blocks to handle potential errors from the Stripe API.

Key Points

  • API Version: The code uses apiVersion: '2024-12-18.acacia'. It’s recommended to use the latest API version.
  • Asynchronous Operations: The Stripe SDK uses promises, so you need to use async/await or .then() to handle the asynchronous calls.
  • Error Handling: Always implement proper error handling to gracefully handle issues with the Stripe API.
  • Environment Variables: Store your secret key in an environment variable.
  • TypeScript: This code is written in TypeScript, which provides type safety and code completion.
  • Flexibility: This is a basic example. You can customize it further by adding more parameters to the API calls, such as discounts, tax rates, shipping costs, etc.

Remember to

  1. Replace process.env.STRIPE_SECRET_KEY with your actual secret key or use a secure way to manage your API keys.
  2. Adjust the parameters to the API calls to match your specific needs.
  3. Handle errors properly in your application.

This should give you a good understanding of Stripe’s API for generating and sending invoices. I suggest you look into the Stripe API Reference for more information on the available methods and parameters.

Final Thoughts

As you see, automatically generating and sending invoices is a really simple process with Stripe’s API. Additionally, if you’re interested in learning more about using their API, you can check out our other blog posts on Adding Coupon Codes to Stripe Checkout and Stripe Checkout with Remix.