Commet
  • Pricing
Log InTry out
Introduction

Subscription Events

subscription.createdsubscription.activatedsubscription.reactivatedsubscription.canceledsubscription.updatedsubscription.plan_changedsubscription.cancellation_scheduledsubscription.cancellation_revokedsubscription.plan_change_scheduledsubscription.plan_change_revokedsubscription.past_due

Trial Events

trial.startedtrial.convertedtrial.expiredtrial.will_endtrial.checkout_ready

Checkout Events

checkout.ready

Payment Events

payment.receivedpayment.failedpayment.recoveredpayment.retry_failedpayment.refundedpayment.disputedpayment.dispute_resolved

Payment Link Events

payment_link.createdpayment_link.completedpayment_link.failedpayment_link.canceled

Invoice Events

invoice.createdinvoice.upcominginvoice.overdueinvoice.voided

Payment Method Events

payment_method.attachedpayment_method.updated

Customer Events

customer.createdcustomer.updatedcustomer.state_changed

Credits & Balance Events

credits.grantedcredits.purchasedcredits.lowcredits.depletedcredits.expiredbalance.topped_upbalance.lowbalance.depleted

Quota & Usage Events

quota.threshold_reachedquota.exceededusage.recorded

Seat Events

seats.updatedseats.limit_reached

Add-on Events

addon.activatedaddon.deactivated

Payout Events

payout.availablepayout.createdpayout.paidpayout.failed
System status
DocumentationKnowledge BaseBuild with AIAPI ReferenceWebhooks

customer.state_changed

Aggregate entitlement event — what can this customer access right now.

Payload

All webhook payloads follow a consistent top-level structure with event-specific data nested within the data object.

customerIdstring

The customer ID. Returns your externalId if you provided one when creating the customer, otherwise returns the Commet publicId.

triggerstring

What caused the transition. One of: subscription_created, subscription_activated, subscription_canceled, plan_change, past_due, trial_started, trial_converted, trial_expired, cancellation_scheduled, cancellation_revoked, seats_updated, addon_activated, addon_deactivated, credits_depleted, balance_depleted, quota_exceeded.

statusstring

The customer's current subscription status, or "none" when no live subscription exists. Access is granted while trialing, active, or past_due — past_due is a permissive grace window during dunning.

subscriptionIdstring | null

The live subscription ID, or null when status is none.

planWebhookPlanRef | null

The current plan (id and name), or null when status is none.

billingIntervalstring | null

The current billing interval.

consumptionModelstring | null

The plan's consumption model: metered, credits, or balance.

featuresWebhookFeatureAccess[]

Current feature access, one entry per plan feature: code, name, type, allowed, enabled, current, included, remaining, overageQuantity, overageUnitPrice, unlimited, overageEnabled, billedQuantity. Fields that do not apply to a feature type are null.

seatsWebhookSeatSummary[]

Summary of seats-type features: code, current, included, remaining, unlimited.

creditsWebhookCreditsBalance | null

For credits plans: planCredits, purchasedCredits, totalCredits. Null otherwise.

balanceWebhookBalance | null

For balance plans: currentBalance in rate scale (10000 = $1.00). Null otherwise.

{
  "event": "customer.state_changed",
  "timestamp": "2026-06-23T14:30:00.000Z",
  "organizationId": "8f14e45f-ceea-4e7a-9c3d-1c2b3a4d5e6f",
  "mode": "live",
  "apiVersion": "2026-07-11",
  "data": {
    "customerId": "user_123",
    "trigger": "subscription_activated",
    "status": "active",
    "subscriptionId": "sub_1a2b3c4d",
    "plan": {
      "id": "pln_pro_monthly",
      "name": "Pro"
    },
    "billingInterval": "monthly",
    "consumptionModel": "metered",
    "features": [
      {
        "code": "api_calls",
        "name": "API Calls",
        "type": "usage",
        "allowed": true,
        "enabled": null,
        "current": 120,
        "included": 1000,
        "remaining": 880,
        "overageQuantity": 0,
        "overageUnitPrice": 50,
        "unlimited": false,
        "overageEnabled": true,
        "billedQuantity": null
      },
      {
        "code": "editors",
        "name": "Editors",
        "type": "seats",
        "allowed": true,
        "enabled": null,
        "current": 3,
        "included": 5,
        "remaining": 2,
        "overageQuantity": 0,
        "overageUnitPrice": null,
        "unlimited": false,
        "overageEnabled": false,
        "billedQuantity": null
      }
    ],
    "seats": [
      {
        "code": "editors",
        "current": 3,
        "included": 5,
        "remaining": 2,
        "unlimited": false
      }
    ],
    "credits": null,
    "balance": null
  }
}

One event to sync access

Instead of handling every lifecycle event (subscription.activated, subscription.canceled, trial.expired, ...) to keep your access flags in sync, handle this single event. Every entitlement transition fires it with the customer's current state, computed at delivery time:

triggerWhen
subscription_createdA subscription was created (status pending_payment — no access yet).
subscription_activatedA payment confirmed the subscription.
trial_startedA trial began.
trial_convertedA trialing customer converted to paid via plan change.
trial_expiredA trial ran out and regular billing began.
plan_changeA plan change executed (immediate or scheduled).
cancellation_scheduledA cancellation was scheduled — access continues until period end.
cancellation_revokedA scheduled cancellation was reverted.
subscription_canceledThe subscription terminated — status becomes none.
past_dueA recurring payment failed — a grace window begins: usage and seats keep working, new purchases are blocked.
seats_updatedA customer's seat count changed.
addon_activatedAn add-on was activated on the subscription.
addon_deactivatedAn add-on was deactivated from the subscription.
credits_depletedThe subscription ran out of credits.
balance_depletedThe subscription ran out of prepaid balance.
quota_exceededUsage passed a feature's included quantity.

Handling the payload

Use status as the access gate (trialing and active grant access), features for per-feature limits, and credits/balance for consumption headroom on credits/balance plans. The payload reflects the state at delivery time — if two transitions happen back to back, the later event always carries the final state, so processing events in timestamp order converges to the correct result.

How is this guide?

customer.updated

Fired when a customer's details change. Carries the full current customer resource.

credits.granted

Non-purchase credits were granted to a subscription.