Orange Subscriptions involved using webhooks to process subscription invoices, with a focus on
two key events: invoice.created
and invoice.payment_succeeded
. Testing and documentation
were prioritized to improve reliability compared to previous systems, and Confluence was used
to document processes. Despite some issues during launch, the project was ultimately successful
in providing a reliable digital and physical subscription service for customers. Over the course
of 28 months since launch, it processed around $375,000.
Created as a Senior Software Engineer at The reThinkGroup, Inc.
This project was a deep dive into using webhooks from a receiving and event-processing standpoint.
The main focus was on the specific types of events that were relevant to processing subscription
invoices. One of the main events was invoice.created
, which gathered the appropriate monthly SKU
from Stripe's base_sku
metadata field. The SKU identifier and processing date were attached to
the Stripe invoice object, which allowed for customizing the receipt sent to customers. Another
important event was invoice.payment_succeeded
, leveraged to transform and send the subscription
information to our order management system.
Automated testing and extensive documentation ensured improved reliability over an existing bespoke system. Confluence was leveraged to outline various processes, such as creating subscriptions and products in the Stripe dashboard, including how to set up a local production instance using the Stripe CLI. Additionally, I set up staging and production environments to ensure that any changes we made to the system would not impact our live customers. Failed background jobs also sent alert messages to Slack channels so that issues with processing invoices were handled promptly.
Despite thorough preparation, I still encountered some issues during the launch. The primary issues were that default card information was not present and the scheduled command for fetching monthly SKUs misbehaved. There were also delivery issues, such as order total mismatches and missing metadata. However, I was able to identify these issues and work to fix them promptly with no recurring hiccups. Overall, this project was a success for providing a reliable and seamless digital and physical subscription service for our customers.
In 28 months of service, it processed roughly $375,000, averaging $13,000 per month, with a the peak of 595 invoices at $30,000 and a low of 115 invoices at $6,000.
invoice.created
and invoice.payment_succeeded
.Technologies used on this project
General concepts
Infrastructure
Application-specific
Dashboard with metrics such as our count or revenue generated by product type. Laravel Nova makes it simple to aggregate information for dashboard widgets.
Viewing, filtering, and sorting the list of products. Products are configured here prior to being processed. There are numerous other products in Stripe handling their own reconcilliation with the accounting team.
Viewing the 252 Kids Story Poster
details. The monthly SKU variants are displayed here, including the relevant Stripe metadata, if present.
Editing a particular product by clicking the note icon. Information like the type or frequency are pre-populated based on the enum
type selected.
Viewing the 252 Kids Story Poster Bundle - March, April, May 2023
SKU variant details.
SKUs are automatically populated based on a periodic task that looks for products by their base_sku
field.
While editing SKUs is possible, it is preferred to make changes upstream.
Viewing, filtering, and sorting the list of invoices. Invoices that are processed get displayed on this screen. New invoices get created before their accompanying subscription due to the flow of webhook events.
Viewing, filtering, and sorting the list of subscriptions. This page is less relevant as new subscriptions typically aren't created often. This system primarily covers legacy subscriptions until the Shopify store incorporates the behavior.
Viewing, filtering, and sorting the list of users with access to the system. Users authenticate against the flagship API. User data produces an understanding of who is potentially making changes within the system.
Viewing the Stripe customer details. This is the top-most entity in our relationship tree so a customer's subscriptions, invoices, and payments are listed here. The Stripe payload in JSON, including a link to the customer in the Stripe dashboard, is displayed to aid troubleshooting.
Viewing the Stripe subscription details. This is our primary entity for gathering information to send to our accounting system. A subscription is created in Stripe with the necessary metadata that the system uses to populate the order sent to the accounting system. The Stripe payload in JSON, including a link to the subscription in the Stripe dashboard, is displayed to aid troubleshooting.
Viewing the Stripe invoice details. This is the first entity created by the invoice.created
webhook event that includes partial invoice data.
The Stripe custom fields, metadata, and payload JSON fields are displayed to give us an understanding of what the system processes.
Links to the customer, subscription, invoice, and charge in the Stripe dashboard are displayed to aid in troubleshooting.
Viewing the Stripe payment details. The Stripe metadata field displays the information captured for reconcilliation by the accounting team. Links to the customer, subscription, invoice, and charge in the Stripe dashboard are displayed to aid in troubleshooting.
The Horizon dashboard page that gives us a glance at how our background queues are operating. Laravel Horizon helps us inspect or retry failed jobs along with basic metrics like completion time or number of failures per job.
The requests page in Laravel Telescope. Telescope is leveraged in debugging or to understand how the system is operating as a whole.