## TL;DR

invoice.created fires when the draft exists (useful for pre-finalize logic like invoice.upcoming warnings or custom validation); invoice.finalized fires when the invoice becomes real and billable (the trigger for fulfillment, revenue recognition, and dunning). Most post-billing automation belongs on invoice.finalized; use invoice.created only when you need the draft window. Listening to both without distinguishing them double-triggers flows.

## Steps

1. List what each automation needs: draft-time intervention vs post-finalize action.
   Expected: Each listener gets a justified event.
2. Put pre-finalize logic (warnings, validation, edits) on invoice.created.
   Expected: Draft-window work runs before the invoice is real.
3. Put fulfillment, accounting entries, and dunning on invoice.finalized.
   Expected: Real-invoice work runs exactly once, on a real invoice.
4. Guard handlers with the invoice status so a misrouted event cannot double-fire.
   Expected: Defense in depth against duplicate processing.
5. Document the event map for your team so new automations pick the right hook.
   Expected: Future work inherits the correct pattern.

## When to use

- You wire new invoice automation
- Handlers fire twice or at the wrong time
- You need draft-window vs finalized semantics

## When not to use

- You handle payment outcomes (use invoice.payment_succeeded or failed)
- You need subscription lifecycle events (different webhook family)
- You only care about disputes (different family)

## Compatibility

Stripe webhooks; invoice.created and invoice.finalized event types. All API versions with Billing.

## Variant phrasings

### ### Stripe invoice.created vs finalized

### ### which invoice webhook to use Stripe

### ### invoice finalized webhook fulfillment

## Root cause

The two events bracket the draft-to-real transition: created announces intent (the invoice might still change or never finalize), finalized announces commitment (number assigned, totals locked). Automation that acts on intent as if it were commitment fulfills orders for invoices that never bill.

## Edge cases

- Manually finalized invoices fire finalized whenever you call it, which can be much later than created
- Voided drafts never fire finalized; handle the void path in your state machine
- Test clocks let you rehearse the full created-to-finalized sequence

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_eBWLsrkWHqXeZP2tFF67JQ
