Invoices
Receive notifications when invoices are created, updated, paid, failed, or require payment action.
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": 1704067200,
"data": {
"object": {
"object": "invoice",
"id": 100001,
"address_billing": {
"object": "address",
"id": 45678,
"city": "New York",
"company": "Acme Inc",
"country": "US",
"country_name": "United States",
"created_at": "2024-01-01T00:00:00.000000Z",
"department": null,
"first_name": "John",
"is_default": true,
"last_name": "Doe",
"line1": "123 Main Street",
"line2": "Suite 100",
"postal_code": "10001",
"salutation": "Mr",
"site_ids": [1],
"state": "NY",
"state_name": "New York",
"title": null,
"type": "billing",
"updated_at": "2024-01-01T00:00:00.000000Z"
},
"address_shipping": {
"object": "address",
"id": 45679,
"city": "New York",
"company": "Acme Inc",
"country": "US",
"country_name": "United States",
"created_at": "2024-01-01T00:00:00.000000Z",
"department": null,
"first_name": "John",
"is_default": true,
"last_name": "Doe",
"line1": "123 Main Street",
"line2": "Suite 100",
"postal_code": "10001",
"salutation": "Mr",
"site_ids": [1],
"state": "NY",
"state_name": "New York",
"title": null,
"type": "shipping",
"updated_at": "2024-01-01T00:00:00.000000Z"
},
"amount_due": 3500,
"amount_paid": 0,
"amount_remaining": 3500,
"auto_advance": true,
"billing": "charge_automatically",
"billing_address": {
"object": "address",
"id": 45678,
"city": "New York",
"company": "Acme Inc",
"country": "US",
"country_name": "United States",
"created_at": "2024-01-01T00:00:00.000000Z",
"department": null,
"first_name": "John",
"is_default": true,
"last_name": "Doe",
"line1": "123 Main Street",
"line2": "Suite 100",
"postal_code": "10001",
"salutation": "Mr",
"site_ids": [1],
"state": "NY",
"state_name": "New York",
"title": null,
"type": "billing",
"updated_at": "2024-01-01T00:00:00.000000Z"
},
"billing_reason": "subscription_cycle",
"charge_id": null,
"created": "2024-01-01T12:00:00.000000Z",
"currency": "usd",
"customer": {
"object": "customer",
"id": 12345,
"balance": 0,
"billing_email": null,
"created": "2023-06-15T09:30:00.000000Z",
"currency": "usd",
"default_source": {
"object": "source",
"id": 700001,
"object_id": "pm_XXXXXXXXXXXXXXXXXXXX",
"object_gateway": "stripe",
"brand": "visa",
"country": "US",
"exp_month": 12,
"exp_year": 2027,
"funding": "credit",
"last4": "4242",
"site_ids": [1]
},
"delinquent": false,
"display_name": null,
"email": "[email protected]",
"email_confirm": null,
"email_hardbounce": false,
"first_name": "John",
"has_password": 1,
"language": "en",
"last_active_at": 1704060000,
"last_login_method": "email",
"last_name": "Doe",
"mail_marketing": null,
"metadata": {
"customer_source": "web"
},
"object_id": "cus_XXXXXXXXXXXXXX",
"organization": null,
"password_last_updated_at": null,
"phone": null,
"phone_confirm": null,
"salutation": "Mr",
"site_ids": [1],
"tele_marketing": null,
"title": null,
"username": null
},
"customer_address": null,
"customer_shipping": {
"id": 45679,
"type": "shipping",
"user_id": 12345,
"account_id": null,
"salutation": "Mr",
"first_name": "John",
"last_name": "Doe",
"title": null,
"company": "Acme Inc",
"department": null,
"line1": "123 Main Street",
"line2": "Suite 100",
"city": "New York",
"state": "NY",
"country": "US",
"postal_code": "10001",
"phone": null,
"metadata": null,
"old_provider_id": null,
"is_default": true,
"pelcro_sync_last_at": null,
"pelcro_sync_failed_reason": null,
"created_at": "2024-01-01T00:00:00.000000Z",
"updated_at": "2024-01-01T00:00:00.000000Z",
"deleted_at": null,
"attributes": null
},
"days_to_creation": 7,
"default_tax_rates": null,
"deleted_at": null,
"discount_id": null,
"ending_balance": 0,
"finalized_at": "2024-01-01T12:00:01.000000Z",
"hosted_invoice_url": null,
"invoice_pdf": "https://www.pelcro.com/pdf/invoice/eyJpdiI6Ik...",
"is_imported": false,
"lines": {
"object": "list",
"data": [
{
"object": "line_item",
"id": 400001,
"amount": 3500,
"created_at": "2024-01-01T12:00:01.000000Z",
"currency": "usd",
"deleted_at": null,
"description": "1 x Monthly Plan (at $35.00 / month)",
"metadata": null,
"object_id": null,
"period": {
"start": 1704067200,
"end": 1706745600
},
"quantity": 1,
"subscription": {
"object": "subscription",
"id": 200001,
"address_id": 45679,
"address_shipping": { "...": "Nested Address object" },
"auto_renew": true,
"billing": "charge_automatically",
"cancel_at_period_end": 0,
"canceled_at": null,
"created": "2023-06-15T09:30:00.000000Z",
"current_period_start": "2024-01-01T09:30:00.000000Z",
"current_period_end": "2024-02-01T09:30:00.000000Z",
"customer": { "...": "Nested Customer object" },
"default_source": { "...": "Nested Source object" },
"latest_invoice": { "...": "Nested Invoice object" },
"plan": { "...": "Full Plan object with nested Product" },
"quantity": 1,
"schedules": { "...": "Subscription schedule phases" },
"site_id": 1,
"status": "active",
"...": "Full subscription object"
},
"tax_amounts": null,
"tax_rates": null,
"updated_at": "2024-01-01T12:00:01.000000Z"
}
]
},
"marked_uncollectible_at": null,
"number": "XXXXXXXX-000001",
"object_id": null,
"paid_at": null,
"payment_link": "https://www.pelcro.com/invoice/payment/eyJpdiI6Ik...",
"period_end": "2024-02-01T09:30:00.000000Z",
"period_start": "2024-01-01T09:30:00.000000Z",
"plan": {
"id": 300001,
"nickname": "Monthly Plan",
"interval": "month"
},
"post_payment_credit_notes_amount": 0,
"pre_payment_credit_notes_amount": 0,
"product": {
"id": 500001,
"name": "Premium Subscription",
"name_internal": null,
"description": "Full access to all premium content",
"entitlements": ["digital"],
"type": "service"
},
"purchase_order": null,
"site_id": 1,
"source": null,
"starting_balance": 0,
"status": "open",
"subscription_id": 200001,
"subtotal": 3500,
"tax": 0,
"tax_percent": null,
"total": 3500,
"total_tax_amounts": null,
"updated_at": "2024-01-01T12:00:01.000000Z",
"voided_at": null
}
}
}Note: The
payment_linkfield is conditional — it is only present when the invoicestatusisopenorpast_due. For invoices with other statuses (e.g.scheduled,paid,void), this field will be absent from the payload entirely.
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": 1704067300,
"data": {
"object": {
"object": "invoice",
"id": 100001,
"amount_due": 3500,
"amount_paid": 3500,
"amount_remaining": 0,
"status": "paid",
"...": "Same full 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": "usd",
"customer": {
"object": "customer",
"id": 12345,
"...": "Full customer object"
},
"days_to_creation": 7,
"plan": {
"id": 300001,
"nickname": "Monthly Plan",
"interval": "month"
},
"product": {
"id": 500001,
"name": "Premium Subscription",
"name_internal": null,
"description": null,
"entitlements": null,
"type": "service"
},
"status": null,
"subscription_id": 200001,
"...": "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": 100001,
"amount_due": 3500,
"amount_paid": 3500,
"amount_remaining": 0,
"charge": {
"id": 600001,
"offline": false,
"payment_category": "card",
"reference": null
},
"paid_at": "2023-02-21T13:10:00.000000Z",
"status": "paid",
"source": {
"object": "source",
"id": 700001,
"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": 100001,
"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": 100001,
"amount_due": 3500,
"amount_paid": 0,
"amount_remaining": 3500,
"hosted_invoice_url": null,
"status": "open",
"...": "Same structure as invoice.created"
}
}
}Note: This event does not include
previous_attributes. Since the invoice status isopen, thepayment_linkfield will be present — use it to 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 | Customer's default billing address, formatted through AddressResource (nested Address object) |
address_shipping | object | null | Shipping address from the subscription, formatted through AddressResource (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 | Customer's first billing-type address, formatted through AddressResource. Equivalent to address_billing — both are sourced from the customer's billing address. |
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") |
customer | object | null | Customer who owns this invoice (nested Customer object) |
customer_address | object | null | Customer's billing address snapshot stored on the invoice at creation time. This is a raw database record — field structure differs from the AddressResource format used in address_billing. Includes internal fields such as user_id, account_id, phone, metadata, old_provider_id, pelcro_sync_last_at, pelcro_sync_failed_reason, deleted_at, and attributes. |
customer_shipping | object | null | Customer's shipping address snapshot stored on the invoice at creation time. This is a raw database record — field structure differs from the AddressResource format used in address_shipping. Includes internal fields such as user_id, account_id, phone, metadata, old_provider_id, pelcro_sync_last_at, pelcro_sync_failed_reason, deleted_at, and attributes. |
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 an externally-hosted invoice page (null for Pelcro Billing Engine accounts) |
invoice_pdf | string | 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 (null for Pelcro Billing Engine accounts) |
order | object | null | Associated order details (for e-commerce invoices) |
paid_at | string | null | Timestamp when the invoice was paid |
payment_link | string | Conditional. URL for the Pelcro-hosted payment page. Only present when status is open or past_due — absent for all other statuses. |
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 | null | External identifier (null for Pelcro Billing Engine accounts) |
period | object | Billing period (start and end as unix timestamps) |
quantity | integer | Quantity of items |
subscription | object | null | Fully expanded subscription object including nested customer, default_source, plan (with product), address_shipping, latest_invoice, and schedules (with phases and phase plans) |
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 |
|---|---|
scheduled | Invoice is scheduled for a future billing cycle and not yet open for payment |
draft | Invoice is a draft and not yet finalized |
open | Invoice is finalized and awaiting payment |
paid | Invoice has been paid in full |
past_due | Invoice is past its due date and still unpaid |
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 20 days ago
