Invoices
Overview
Invoice webhooks notify your application about the lifecycle of invoices. Use these events to track billing activity, notify customers about payments, handle failed charges, and build automated billing workflows.
Use Cases
- Notify customers when a new invoice is generated
- Send payment confirmation emails on successful charges
- Trigger dunning workflows when payments fail
- Alert customers when payment action (e.g. 3D Secure) is required
- Build dashboards to track billing metrics and revenue
- Send advance notice to customers about upcoming invoices
Events
| Event | Description |
|---|---|
invoice.created | A new invoice was generated |
invoice.updated | An invoice was updated (e.g. status change, payment applied) |
invoice.upcoming | An invoice will be generated soon for an upcoming billing cycle |
invoice.payment_succeeded | Payment was successfully collected for an invoice |
invoice.payment_failed | Payment collection failed for an invoice |
invoice.payment_action_required | Customer action is required to complete payment (e.g. 3D Secure authentication) |
invoice.created
Triggered When
- A subscription is created and its first invoice is generated
- A subscription renews and a new billing cycle invoice is created
- An invoice is manually created via the API or dashboard
Payload
{
"type": "invoice.created",
"id": "evt_HAg8TfEfmhE55hZ3ot6kZ7d2",
"created": 1676984809,
"data": {
"object": {
"object": "invoice",
"id": 2947310,
"address_billing": null,
"address_shipping": null,
"amount_due": 3500,
"amount_paid": 0,
"amount_remaining": 3500,
"auto_advance": true,
"billing": "send_invoice",
"billing_address": null,
"billing_reason": "subscription_create",
"charge_id": null,
"created": "2023-02-21T13:06:47.000000Z",
"currency": "cad",
"customer": {
"object": "customer",
"id": 8194391,
"balance": 0,
"created": "2023-02-20T13:44:08.000000Z",
"currency": "cad",
"default_source": null,
"delinquent": false,
"display_name": null,
"email": "[email protected]",
"email_confirm": null,
"email_hardbounce": false,
"first_name": "John",
"has_password": 0,
"language": null,
"last_login_method": null,
"last_name": "Doe",
"metadata": null,
"object_id": "cus_NOMNc5o5JjBPUi",
"organization": null,
"password_last_updated_at": null,
"phone": null,
"phone_confirm": null,
"salutation": null,
"site_ids": [775],
"title": null,
"username": null
},
"customer_address": null,
"customer_shipping": null,
"days_to_creation": 7,
"default_tax_rates": null,
"deleted_at": null,
"discount_id": null,
"ending_balance": 0,
"finalized_at": "2023-02-21T13:06:47.000000Z",
"hosted_invoice_url": "https://invoice.stripe.com/i/...",
"invoice_pdf": "https://example.pelcro.com/pdf/invoice/...",
"is_imported": null,
"lines": {
"object": "list",
"data": [
{
"object": "line_item",
"id": 3408896,
"amount": 3500,
"created_at": "2023-02-21T13:06:48.000000Z",
"currency": "cad",
"deleted_at": null,
"description": "1 x Monthly Plan (at $35.00 / month)",
"metadata": null,
"object_id": "il_1MdvYRJSYlEHeD4bxqH3BaCK",
"period": {
"end": 1677589606,
"start": 1676984806
},
"quantity": 1,
"subscription": {
"object": "subscription",
"id": 2896258,
"billing": "send_invoice",
"cancel_at_period_end": 0,
"canceled_at": null,
"created": "2023-02-21T13:06:46.000000Z",
"current_period_start": "2023-02-21T13:06:46.000000Z",
"current_period_end": "2023-02-28T13:06:46.000000Z",
"plan": { "..." : "..." }
},
"tax_amounts": null,
"tax_rates": null,
"updated_at": "2023-02-21T13:06:48.000000Z"
}
]
},
"marked_uncollectible_at": null,
"number": "3D68210F-0006",
"object_id": "in_1MdvYRJSYlEHeD4bbYnkFUcL",
"paid_at": null,
"payment_link": "https://example.pelcro.com/invoice/payment/...",
"period_end": "2023-02-21T13:06:46.000000Z",
"period_start": "2023-02-21T13:06:46.000000Z",
"plan": {
"id": 374852,
"nickname": "Monthly Plan",
"interval": "month"
},
"post_payment_credit_notes_amount": 0,
"pre_payment_credit_notes_amount": 0,
"product": {
"id": 4857,
"name": "Premium Subscription",
"name_internal": null,
"description": null,
"entitlements": null,
"type": "service"
},
"purchase_order": null,
"site_id": 775,
"source": null,
"starting_balance": 0,
"status": "open",
"subscription_id": 2896258,
"subtotal": 3500,
"tax": null,
"tax_percent": null,
"total": 3500,
"total_tax_amounts": null,
"updated_at": "2023-02-21T13:06:49.000000Z",
"voided_at": null
}
}
}invoice.updated
Triggered When
- An invoice's status changes (e.g. from
opentopaid) - Invoice fields are modified (e.g. amount adjustments, metadata changes)
Payload
{
"type": "invoice.updated",
"id": "evt_Kp9xMfEfmhE55hZ3ot6kZ7d3",
"created": 1676984900,
"data": {
"object": {
"object": "invoice",
"id": 2947310,
"amount_due": 3500,
"amount_paid": 3500,
"amount_remaining": 0,
"status": "paid",
"...": "Same structure as invoice.created"
},
"previous_attributes": {
"amount_paid": 0,
"amount_remaining": 3500,
"status": "open"
}
}
}Note: The
previous_attributesobject contains only the fields that changed, showing their values before the update. Only fields listed in the invoice's publishable attributes are included.
invoice.upcoming
Triggered When
- A subscription's billing cycle is approaching and an invoice will be generated soon
- The number of days before the invoice is created is determined by the plan's
invoice_upcoming_notificationsetting or the account-levelinvoice_upcoming_notification_dayssetting
Payload
{
"type": "invoice.upcoming",
"id": "evt_Rq7xNgGhmjF66iA4pt7lA8e4",
"created": 1676900000,
"data": {
"object": {
"object": "invoice",
"id": null,
"amount_due": 3500,
"amount_paid": 0,
"amount_remaining": 3500,
"currency": "cad",
"customer": {
"object": "customer",
"id": 8194391,
"...": "Full customer object"
},
"days_to_creation": 7,
"plan": {
"id": 374852,
"nickname": "Monthly Plan",
"interval": "month"
},
"product": {
"id": 4857,
"name": "Premium Subscription",
"name_internal": null,
"description": null,
"entitlements": null,
"type": "service"
},
"status": null,
"subscription_id": 2896258,
"...": "Same structure as invoice.created"
}
}
}Note: The
invoice.upcomingevent represents a preview of the upcoming invoice. The invoiceidmay benullsince the invoice has not been created yet. Thedays_to_creationfield indicates how many days until the invoice will be generated.
invoice.payment_succeeded
Triggered When
- Payment is successfully collected for an invoice
- The invoice status transitions to
paid
Payload
{
"type": "invoice.payment_succeeded",
"id": "evt_Xt5yPqHinlG77jB5qu8mB9f5",
"created": 1676985000,
"data": {
"object": {
"object": "invoice",
"id": 2947310,
"amount_due": 3500,
"amount_paid": 3500,
"amount_remaining": 0,
"charge": {
"id": 1234567,
"offline": false,
"payment_category": "card",
"reference": null
},
"paid_at": "2023-02-21T13:10:00.000000Z",
"status": "paid",
"source": {
"object": "source",
"id": 567890,
"brand": "Visa",
"country": "US",
"exp_month": 12,
"exp_year": 2025,
"last_four": "4242",
"type": "card"
},
"...": "Same structure as invoice.created"
},
"previous_attributes": {
"amount_paid": 0,
"amount_remaining": 3500,
"status": "open"
}
}
}Note: The
previous_attributesobject is automatically detected from model changes. It contains the invoice fields that changed during the payment process, with their previous values. Thechargeandsourceobjects are included when a payment method was used.
invoice.payment_failed
Triggered When
- An attempt to collect payment for an invoice fails
- Common causes include insufficient funds, expired cards, or declined transactions
Payload
{
"type": "invoice.payment_failed",
"id": "evt_Zu6zRsJjomH88kC6rv9nC0g6",
"created": 1676985100,
"data": {
"object": {
"object": "invoice",
"id": 2947310,
"amount_due": 3500,
"amount_paid": 0,
"amount_remaining": 3500,
"status": "open",
"...": "Same structure as invoice.created"
},
"previous_attributes": {
"status": "open"
}
}
}Note: The
previous_attributesobject is automatically detected from model changes. If no publishable fields changed during the failed payment attempt,previous_attributeswill be an empty object.
invoice.payment_action_required
Triggered When
- Payment requires additional customer action to complete (e.g. 3D Secure authentication, bank redirect)
- The payment gateway returns a
requires_actionstatus
Payload
{
"type": "invoice.payment_action_required",
"id": "evt_Av7ARtKkpnI99lD7sw0oD1h7",
"created": 1676985200,
"data": {
"object": {
"object": "invoice",
"id": 2947310,
"amount_due": 3500,
"amount_paid": 0,
"amount_remaining": 3500,
"hosted_invoice_url": "https://invoice.stripe.com/i/...",
"status": "open",
"...": "Same structure as invoice.created"
}
}
}Note: This event does not include
previous_attributes. Use thehosted_invoice_urlto redirect the customer to complete the required payment action.
Payload Fields
All invoice events share the same core payload structure under data.object. Fields are sorted alphabetically with object and id prepended.
Invoice Object
| Field | Type | Description |
|---|---|---|
object | string | Always "invoice" |
id | integer | The invoice ID |
address_billing | object | null | Default billing address (nested Address object) |
address_shipping | object | null | Shipping address from subscription (nested Address object) |
amount_due | integer | Amount in cents that is owed on this invoice |
amount_paid | integer | Amount in cents that has been paid |
amount_remaining | integer | Amount in cents remaining to be paid |
auto_advance | boolean | Whether the invoice will automatically advance to the next status |
billing | string | integer | Collection method ("charge_automatically" or "send_invoice") |
billing_address | object | null | Legacy billing address (deprecated, use address_billing) |
billing_reason | string | null | Reason the invoice was created (e.g. "subscription_create", "subscription_cycle") |
charge | object | null | Associated charge details (present when a payment was attempted) |
charge_id | integer | null | Associated charge ID |
coupon | object | null | Applied coupon details (when a discount is applied) |
created | string | Timestamp when the invoice was created |
currency | string | Three-letter ISO currency code (e.g. "usd", "cad") |
customer | object | null | Customer who owns this invoice (nested Customer object) |
customer_address | object | null | Customer's address at the time of invoicing |
customer_shipping | object | null | Customer's shipping information at the time of invoicing |
days_to_creation | integer | null | Days until the invoice will be created (for upcoming invoices) |
default_tax_rates | object | null | Default tax rates applied to the invoice |
deleted_at | string | null | Timestamp when the invoice was deleted (soft delete) |
discount_id | integer | null | Applied discount ID |
ending_balance | integer | Customer's ending balance after the invoice is finalized |
finalized_at | string | null | Timestamp when the invoice was finalized |
hosted_invoice_url | string | null | URL for the Stripe-hosted invoice page |
invoice_pdf | string | null | URL to download the invoice PDF |
is_imported | boolean | null | Whether the invoice was imported from an external system |
lines | object | null | Invoice line items (nested list of Line Item objects) |
marked_uncollectible_at | string | null | Timestamp when the invoice was marked uncollectible |
number | string | null | Unique invoice number |
object_id | string | null | External identifier (e.g. Stripe invoice ID) |
order | object | null | Associated order details (for e-commerce invoices) |
paid_at | string | null | Timestamp when the invoice was paid |
payment_link | string | URL for the Pelcro-hosted payment page (only for open/past-due invoices) |
period_end | string | End of the billing period covered by the invoice |
period_start | string | Start of the billing period covered by the invoice |
plan | object | Associated plan details (id, nickname, interval) |
post_payment_credit_notes_amount | integer | Total amount of credit notes issued after payment |
pre_payment_credit_notes_amount | integer | Total amount of credit notes issued before payment |
product | object | Associated product details (id, name, name_internal, description, entitlements, type) |
purchase_order | string | null | Purchase order number |
site_id | integer | Site ID where the invoice was created |
source | object | null | Payment source used (nested Source object) |
starting_balance | integer | Customer's starting balance before the invoice |
status | string | Invoice status (see Invoice Statuses below) |
subscription_id | integer | null | Associated subscription ID |
subtotal | integer | Subtotal in cents before tax and discounts |
tax | integer | null | Total tax amount in cents |
tax_percent | number | null | Tax percentage applied |
total | integer | Total amount in cents |
total_tax_amounts | object | null | Breakdown of tax amounts by rate |
updated_at | string | Timestamp when the invoice was last updated |
voided_at | string | null | Timestamp when the invoice was voided |
Line Item Object
Each line item in the lines.data array contains:
| Field | Type | Description |
|---|---|---|
object | string | Always "line_item" |
id | integer | Line item ID |
amount | integer | Amount in cents for this line item |
created_at | string | Timestamp when the line item was created |
currency | string | Three-letter ISO currency code |
description | string | null | Description of the line item |
metadata | object | null | Additional metadata |
object_id | string | External identifier |
period | object | Billing period (start and end as unix timestamps) |
quantity | integer | Quantity of items |
subscription | object | null | Nested subscription object |
tax_amounts | object | null | Tax amounts for this line item |
tax_rates | object | null | Tax rates applied to this line item |
Charge Object
When a payment was attempted, the charge object includes:
| Field | Type | Description |
|---|---|---|
id | integer | Charge ID |
offline | boolean | Whether this was an offline payment |
payment_category | string | Payment method category (e.g. "card", "bank") |
reference | string | null | External payment reference |
Invoice Statuses
| Status | Description |
|---|---|
draft | Invoice is a draft and not yet finalized |
open | Invoice is finalized and awaiting payment |
paid | Invoice has been paid in full |
uncollectible | Invoice has been marked as uncollectible |
void | Invoice has been voided |
Events with Previous Attributes
The following events include a previous_attributes object showing changed field values before the update:
| Event | How Previous Attributes Are Determined |
|---|---|
invoice.updated | Passed explicitly from the domain event — contains the previous values of changed publishable fields |
invoice.payment_succeeded | Auto-detected from model changes via getChanges() — filtered to publishable fields only |
invoice.payment_failed | Auto-detected from model changes via getChanges() — filtered to publishable fields only |
Events without previous_attributes: invoice.created, invoice.upcoming, invoice.payment_action_required.
Invoice Lifecycle
The typical lifecycle of an invoice follows one of these sequences:
Successful payment (charge automatically):
invoice.created- Invoice generatedinvoice.payment_succeeded- Payment collectedinvoice.updated- Status changed topaid
Successful payment (send invoice):
invoice.upcoming- Advance notice of upcoming invoiceinvoice.created- Invoice generated and sentinvoice.payment_succeeded- Customer pays the invoiceinvoice.updated- Status changed topaid
Failed payment:
invoice.created- Invoice generatedinvoice.payment_failed- Payment attempt failedinvoice.updated- Status may change (e.g. touncollectible)
Payment requiring action (3D Secure):
invoice.created- Invoice generatedinvoice.payment_action_required- Customer must complete authenticationinvoice.payment_succeeded- Payment completed after authenticationinvoice.updated- Status changed topaid
Updated about 3 hours ago
