The Problem: Your sales team marks a deal as "Closed Won". Great. Now someone (usually the founder) has to log into QuickBooks, create an invoice, convert to PDF, email it, and then check the bank account every day until it hits.
This "Admin Gap" delays revenue and makes your company look small.
The Automated Architecture
We solve this by decoupling the "Sales" event from the "Finance" event using a middleware (serverless function or n8n).
- Trigger: HubSpot Deal Stage change to "Closed Won".
- Action 1: Look up Customer in Stripe (or create if new).
- Action 2: Create Stripe Invoice with line items from HubSpot Deal.
- Action 3: Automatically email the hosted payment page to the customer.
Handling Taxes & Line Items
The trickiest part is mapping line items. HubSpot products needs to map to Stripe Price IDs. I recommend storing the `stripe_price_id` in a custom property on the HubSpot Product object.
const lineItems = hubspotDeal.line_items.map(item => ({
price: item.properties.stripe_price_id,
quantity: item.quantity,
}));
await stripe.invoices.create({
customer: customerId,
collection_method: 'send_invoice',
days_until_due: 30,
lines: lineItems
});
Why this beats native integrations
Native integrations often break when you have complex discount rules or need to split payments (50% now, 50% later). By building a custom handler, we can apply specific logic:
- Deposit Logic: If deal > $10k, split into two invoices.
- Slack Alerts: Post to #finance-alerts when the invoice is created AND paid.
- Dunning: Use Stripe's built-in dunning for automated follow-ups.
Need this workflow?
I build this exact Invoice Automation System in 7 days. You get the code, the webhooks, and the peace of mind.
The Result
Founders save ~5 hours/week on bookkeeping. But more importantly, cash collection speeds up by 40% because the invoice hits the client's inbox 30 seconds after they say "Yes."