> ## Documentation Index
> Fetch the complete documentation index at: https://docs.macropay.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhook Events

> Every webhook Macropay emits — what fires, when, and how to react to it in your billing logic.

Webhooks are how your app stays in sync with everything happening inside Macropay — a checkout opening, a card clearing, a subscription lapsing, a benefit being revoked. Because Macropay is the **Merchant of Record**, many of these events also reflect work we handle on your behalf: tax/VAT collection, dispute management, and payment retries. You consume the event; we carry the compliance.

This page is the catalog. Events are grouped by what they touch — money moving through a customer's lifecycle (**Billing**) and changes to your own catalog and account (**Organization**). Each card links to the full payload schema in the [API reference](/api-reference/webhooks/order.created).

<Tip>
  Subscribe to the narrowest events that satisfy your use case. Listening to a
  catch-all like `subscription.updated` is convenient, but the specific events
  (`subscription.canceled`, `order.paid`, etc.) make your handlers far easier to
  reason about.
</Tip>

## Billing events

### Checkout

The session a customer moves through to pay. Useful for analytics, abandoned-checkout recovery, and pre-filling your own records before the order lands.

<Columns cols={2}>
  <Card title="checkout.created" icon="link" href="/api-reference/webhooks/checkout.created" horizontal>
    A checkout session was opened.
  </Card>

  <Card title="checkout.updated" icon="link" href="/api-reference/webhooks/checkout.updated" horizontal>
    A checkout session changed status (e.g. confirmed or expired).
  </Card>
</Columns>

### Customers

Track the people and organizations buying from you. `customer.state_changed` is the one to reach for when you need a single source of truth.

<Columns cols={2}>
  <Card title="customer.created" icon="link" href="/api-reference/webhooks/customer.created" horizontal>
    A new customer record exists.
  </Card>

  <Card title="customer.updated" icon="link" href="/api-reference/webhooks/customer.updated" horizontal>
    Customer details were edited.
  </Card>

  <Card title="customer.deleted" icon="link" href="/api-reference/webhooks/customer.deleted" horizontal>
    A customer was removed.
  </Card>

  <Card title="customer.state_changed" icon="link" href="/api-reference/webhooks/customer.state_changed" horizontal>
    A consolidated snapshot whenever anything material changes — active
    subscriptions and currently granted benefits included.
  </Card>
</Columns>

<Note>
  For provisioning access, `customer.state_changed` is usually all you need: the
  payload tells you exactly what the customer is entitled to right now, so you can
  reconcile your own access table in one place instead of stitching together
  subscription and benefit events.
</Note>

### Subscriptions

Recurring billing has the most moving parts, so it has the most events. Start here when implementing any subscription logic.

<Columns cols={2}>
  <Card title="subscription.created" icon="link" href="/api-reference/webhooks/subscription.created" horizontal>
    A subscription was created.
  </Card>

  <Card title="subscription.active" icon="link" href="/api-reference/webhooks/subscription.active" horizontal>
    The subscription is active and billing.
  </Card>

  <Card title="subscription.uncanceled" icon="link" href="/api-reference/webhooks/subscription.uncanceled" horizontal>
    A scheduled cancellation was reversed.
  </Card>

  <Card title="subscription.canceled" icon="link" href="/api-reference/webhooks/subscription.canceled" horizontal>
    The subscription is set to cancel (or has canceled).
  </Card>

  <Card title="subscription.past_due" icon="link" href="/api-reference/webhooks/subscription.past_due" horizontal>
    A renewal payment failed. The customer can recover by updating their payment
    method — we retry automatically.
  </Card>

  <Card title="subscription.updated" icon="link" href="/api-reference/webhooks/subscription.updated" horizontal>
    Catch-all that fires alongside every other subscription event
    (`active`, `canceled`, `uncanceled`, `past_due`, `revoked`). Handy when you
    want one handler for all state transitions.
  </Card>

  <Card title="order.created" icon="link" href="/api-reference/webhooks/order.created" horizontal>
    Inspect the `billing_reason` field to tell renewals apart: `purchase`,
    `subscription_create`, `subscription_cycle`, or `subscription_update`.
    `subscription_cycle` means a renewal.
  </Card>

  <Card title="subscription.revoked" icon="link" href="/api-reference/webhooks/subscription.revoked" horizontal>
    Billing has stopped and benefits are gone — cut off access here.
  </Card>
</Columns>

#### Cancellation flow

What fires on cancellation depends on whether it takes effect at the end of the billing period (the default) or immediately.

<Tabs>
  <Tab title="End of period (default)">
    A customer cancels from the portal, or you cancel via the dashboard or API.
    Two events fire **right away**:

    1. `subscription.updated`
    2. `subscription.canceled`

    Both carry identical subscription data. The subscription stays in `active`
    status, but `cancel_at_period_end` is now `true` — so keep access on until
    the period ends.

    When the current period closes, the subscription is revoked for good: billing
    cycles stop and benefits are withdrawn. Two more events fire:

    3. `subscription.updated`
    4. `subscription.revoked`

    Both carry identical data, and the status is now `canceled`.
  </Tab>

  <Tab title="Immediate revocation">
    When you cancel with **immediate revocation**, everything fires at once:

    1. `subscription.updated`
    2. `subscription.canceled`
    3. `subscription.revoked`

    All three carry identical data and the status is `canceled` immediately. Revoke
    access on `subscription.revoked`.
  </Tab>
</Tabs>

#### Renewal flow

Each renewal cycle emits events in a fixed order so you can track the cycle from invoice to payment.

<Steps>
  <Step title="Cycle opens">
    At the renewal date, these fire immediately (if enabled on your endpoint):

    1. `subscription.updated`
    2. `order.created`

    The subscription now reflects the new `current_period_start` and
    `current_period_end`. The order is the invoice for the upcoming cycle with a
    `pending` status. If the plan uses **usage-based billing**, the customer's
    metered consumption for the prior period is already rolled into the total.
  </Step>

  <Step title="Payment clears">
    We charge the new order shortly after. On success:

    3. `order.updated`
    4. `order.paid`

    Both carry the same order data, now with status `paid`. Treat `order.paid` as
    the green light to extend service for the new period.
  </Step>
</Steps>

<Info>
  Metered, outcome, and agent-based plans settle through this same renewal flow.
  The `order.created` total for a usage plan already includes everything ingested
  through your meters during the period — including AI usage billed by tokens,
  activity, or verified outcome — so there is no separate "usage" event to
  reconcile. See [usage-based billing](/features/usage-based-billing/introduction)
  for how that consumption is aggregated.
</Info>

### Orders

A one-time purchase or a subscription invoice. These are your canonical revenue events.

<Columns cols={2}>
  <Card title="order.created" icon="link" href="/api-reference/webhooks/order.created" horizontal>
    An order (invoice) was created.
  </Card>

  <Card title="order.paid" icon="link" href="/api-reference/webhooks/order.paid" horizontal>
    Payment cleared — recognize revenue and fulfill here.
  </Card>

  <Card title="order.updated" icon="link" href="/api-reference/webhooks/order.updated" horizontal>
    An order's status or details changed.
  </Card>

  <Card title="order.refunded" icon="link" href="/api-reference/webhooks/order.refunded" horizontal>
    An order was fully or partially refunded.
  </Card>
</Columns>

### Refunds

Standalone refund lifecycle events, complementing `order.refunded`.

<Columns cols={2}>
  <Card title="refund.created" icon="link" href="/api-reference/webhooks/refund.created" horizontal>
    A refund was initiated.
  </Card>

  <Card title="refund.updated" icon="link" href="/api-reference/webhooks/refund.updated" horizontal>
    A refund's status changed.
  </Card>
</Columns>

### Benefit grants

A grant is one customer's access to one benefit — a license key, file download, Discord role, GitHub repo, or prepaid credits. These are your provisioning hooks.

<Columns cols={2}>
  <Card title="benefit_grant.created" icon="link" href="/api-reference/webhooks/benefit_grant.created" horizontal>
    A benefit was granted to a customer — provision access.
  </Card>

  <Card title="benefit_grant.updated" icon="link" href="/api-reference/webhooks/benefit_grant.updated" horizontal>
    A grant changed.
  </Card>

  <Card title="benefit_grant.revoked" icon="link" href="/api-reference/webhooks/benefit_grant.revoked" horizontal>
    A benefit was revoked — tear down the access you provisioned.
  </Card>
</Columns>

## Organization events

These track changes to your own catalog and account rather than a customer transaction — useful for keeping internal dashboards, caches, or read models in step with the dashboard and API.

### Benefits

<Columns cols={2}>
  <Card title="benefit.created" icon="link" href="/api-reference/webhooks/benefit.created" horizontal>
    A benefit definition was created.
  </Card>

  <Card title="benefit.updated" icon="link" href="/api-reference/webhooks/benefit.updated" horizontal>
    A benefit definition changed.
  </Card>
</Columns>

### Products

<Columns cols={2}>
  <Card title="product.created" icon="link" href="/api-reference/webhooks/product.created" horizontal>
    A product was created.
  </Card>

  <Card title="product.updated" icon="link" href="/api-reference/webhooks/product.updated" horizontal>
    A product's details or pricing changed.
  </Card>
</Columns>

### Organization

<Columns cols={2}>
  <Card title="organization.updated" icon="link" href="/api-reference/webhooks/organization.updated" horizontal>
    Your organization's settings changed.
  </Card>
</Columns>
