Events are grouped by aggregate type. Subscribe to specific types or to
a prefix (subscription.*) — never * in production.
Subscriptions
| Event | When |
|---|
subscription.created | Object created (any state). |
subscription.activated | Transitioned to active. |
subscription.trial_started | Entered trialing. |
subscription.trial_will_end | T-3 days before trial end. |
subscription.trial_ended | Trial ended; transitioned to active or past_due. |
subscription.trial_extended | Trial end pushed out by extend-trial. |
subscription.updated | Plan, quantity, metadata, or other fields changed. |
subscription.paused | Entered paused. |
subscription.resumed | Returned to active from paused. |
subscription.past_due | A payment failed; entered past_due. |
subscription.dunning_attempt | A dunning retry was issued. |
subscription.dunning_recovered | Dunning succeeded; back to active. |
subscription.dunning_exhausted | Dunning policy ran out. |
subscription.canceled | Entered canceled. |
subscription.reactivated | Cancellation was reversed before period end. |
subscription.commitment_started | Commitment block began. |
subscription.commitment_renewed | Commitment auto-renewed. |
subscription.commitment_ending | T-30 days before commitment end. |
subscription.commitment_ended | Commitment block expired. |
subscription.usage_threshold_crossed | Component-configured threshold crossed mid-period. |
subscription.refund_processed | Recognition adjusted after a refund on a subscription invoice. |
Invoices
| Event | When |
|---|
invoice.created | Draft invoice created. |
invoice.updated | Draft invoice edited. |
invoice.finalized | Transitioned to open. |
invoice.paid | Transitioned to paid. |
invoice.payment_failed | A payment attempt against this invoice failed. |
invoice.voided | Transitioned to void. |
invoice.marked_uncollectible | Transitioned to uncollectible. |
invoice.fx_rate_locked | FX rate stamped at finalisation. |
Payments
| Event | When |
|---|
payment.created | A new attempt started. |
payment.requires_action | 3DS / SCA needed; see data.next_action. |
payment.action_completed | Customer completed the action; capture in progress. |
payment.processing | Provider is settling. |
payment.succeeded | Capture succeeded. |
payment.failed | Capture failed; reason in data.last_error. |
payment.canceled | Payment cancelled before capture. |
payment.settled | Funds settled at provider; carries final settlement amount and FX rate. |
payment.charged_back | Customer initiated a chargeback. |
payment.dispute_won | Dispute resolved in your favour. |
payment.dispute_lost | Dispute resolved against you; funds removed. |
Refunds & credit notes
| Event | When |
|---|
refund.created | Refund object created. |
refund.succeeded | Provider returned the funds. |
refund.failed | Provider rejected the refund. |
credit_note.created | A credit note was issued. |
credit_note.refund_succeeded | Cash returned (when outcome: refund). |
credit_note.refund_failed | Refund leg of credit note failed. |
Customers & payment methods
| Event | When |
|---|
customer.created | Customer object created. |
customer.updated | Any customer field changed. |
customer.deleted | Customer marked deleted (soft delete). |
customer.payment_method_attached | Method added. |
customer.payment_method_detached | Method removed. |
customer.tax_id_invalidated | Async tax-ID validation failed. |
customer.external_ref_discovered | RevenueAttribution worker back-linked a previously-orphaned revenue.* event to this customer via email-fingerprint match. Payload: customer_id, tenant_id, provider, external_id, revenue_event_id, discovered_at, discovery_method (v1 value: email_fingerprint; future: manual, oauth_link). |
payment_method.verified | Verify call completed. |
payment_method.expired | Card expired (we detect it). |
Wallets
| Event | When |
|---|
wallet.credited | Balance increased. |
wallet.debited | Balance decreased. |
wallet.auto_topup_succeeded | Auto-top-up captured a payment. |
wallet.auto_topup_failed | Auto-top-up payment failed. |
wallet.below_drift_floor | Balance hit drift_floor and settlement could not complete. |
Catalog
| Event | When |
|---|
product.created / product.updated / product.archived | Product CRUD. |
plan.created / plan.updated / plan.archived | Plan CRUD. |
Discounts
| Event | When |
|---|
coupon.created / coupon.updated / coupon.deleted | Coupon CRUD. |
discount.applied | Coupon attached to a customer / subscription / invoice. |
discount.removed | Detached. |
discount.expired | A repeating discount used its last cycle. |
promotion_code.redeemed | A customer used a public promo code. |
Affiliates
| Event | When |
|---|
affiliate.created / affiliate.updated | Affiliate CRUD. |
commission.accrued | Qualifying payment produced a commission. |
commission.eligible | Hold period elapsed. |
commission.reversed | Originating payment refunded / charged back. |
payout_batch.created | Batch assembled. |
payout_batch.settled | All transfers in the batch succeeded. |
payout_batch.failed | A transfer failed. |
Hosted surfaces
| Event | When |
|---|
checkout.session.created | Session URL was created. |
checkout.session.completed | Customer finished checkout. |
checkout.session.expired | TTL elapsed without completion. |
portal.session.completed | Customer closed the portal; carries summary. |
Multi-source revenue capture
Observability projections from Stripe, Toss, Apple App Store Server
Notifications V2, and Google Play RTDN. These events report what the
upstream provider told us happened — they do not supplant
Revenue recognition (a separate workstream
that owns GAAP/IFRS schedules against Paylera-issued invoices).
Money-bearing events (revenue.captured, revenue.refunded,
revenue.subscription_started, revenue.subscription_renewed,
revenue.one_time_purchase) carry:
amount_minor, currency — normalised to your tenant’s reporting
currency.
source_amount_minor, source_currency — as observed at the
provider.
fx_rate_used — string-encoded decimal (precision-preserving).
Lifecycle events (subscription_canceled,
subscription_grace_period_entered, subscription_expired) carry
no money fields. revenue.subscription_recovered carries money
(the renewal that broke the grace period).
revenue.refunded carries a positive amount_minor; the refund
nature is conveyed by the event type, not by a negative amount.
For the full canonical payload shape per event, see
docs/billing_specs/billing_event_catalog/payload_schemas.yaml in the
monorepo.
| Event | When |
|---|
revenue.captured | Money captured (charge succeeded). |
revenue.refunded | Refund issued. amount_minor is positive; the event type conveys “this is a refund”. |
revenue.subscription_started | Initial subscription purchase. |
revenue.subscription_renewed | Recurring renewal succeeded. |
revenue.subscription_canceled | Subscription canceled (lifecycle, no money fields). |
revenue.subscription_grace_period_entered | Payment failed; billing in grace period (lifecycle, no money fields). |
revenue.subscription_recovered | Grace-period recovery: subscription resumed paid status. |
revenue.subscription_expired | Subscription ended (lifecycle completion, no money fields). |
revenue.one_time_purchase | One-time IAP / one-shot purchase. |
revenue.unknown_currency_seen | Ops-only alert: an unknown ISO currency code was observed (forward-compat; producer wires when FX coverage table lands). |
Revenue recognition
| Event | When |
|---|
revrec.schedule_created | Schedule attached to a paid invoice. |
revrec.schedule_adjusted | Refund / credit note changed a schedule. |
revrec.period_closed | A close transaction committed. |
revrec.period_close_failed | A close was attempted and failed. |
| Event | When |
|---|
webhook_endpoint.delivery_failed | A delivery exhausted retries. |
webhook_endpoint.disabled | An endpoint was disabled (manual or after sustained 4xx). |
Payload schema
Every event’s data is the full canonical representation of the
aggregate at the moment of the change. For example, invoice.paid
carries the entire invoice including line items, totals, and
payments — not just the changed fields. This means your handler can
decide whether to re-fetch (for subscription.updated, you usually
should — events for the same subscription may interleave with
subscription.updated events you care about) or trust the payload
(for invoice.paid, the snapshot is authoritative).
previous_attributes is included only on *.updated events and lists
the fields that changed with their pre-change values.
Schema versioning
Every event carries schema_version. Within a major version, fields
are added freely; never removed or renamed. A new major version
(schema_version: 2) ships behind a separate event type
(subscription.activated.v2) with overlap, deprecation header, and
sunset date — the same versioning policy as the API. See
Versioning.