Credit balance changed

Know when a tenant's usage credits are blocked, added or used, so your application can stop or resume usage

When a subscription pays for usage with credits, Bunny keeps a credit balance for it. Bunny sends a CreditBalanceChanged webhook to your platform every time that balance changes, so your application can stop serving a tenant whose credits ran out and serve them again once credits are added.

Enabling the webhookLink to Enabling the webhook section

To enable this webhook you need a webhook endpoint for your platform in Bunny.

Then turn on Credit balance changes enabled on your platform. The webhook is off until you turn it on.

When the webhook is sentLink to When the webhook is sent section

Bunny sends the webhook whenever a credit balance’s state or balance changes. That includes:

  • Usage drawing credits down, and usage blocking the balance when it runs out.
  • Credits added, such as a grant, a top-up, included credits or credits returned from an invoice.
  • Credits removed other than by usage, such as an expiry or a void.
  • Credits becoming usable, when a grant with a later start date starts.

Usage sends one webhook each time it draws credits down, so a busy tenant sends many webhooks.

Balance statesLink to Balance states section

State Meaning
ok Credits are available.
depleted No credits are left, but usage continues and is billed as overage.
blocked No credits are left and usage is blocked until credits are added. Your application should stop usage.

A balance blocks when its usage charge’s depletion policy is block, or top_up while the top-up is being bought. With overage, it becomes depleted instead.

The webhook payloadLink to The webhook payload section

{
  "type": "CreditBalanceChanged",
  "payload": {
    "tenant": {
      "id": 23500,
      "code": "superdesk-1234",
      "name": "Superdesk Inc",
      "subdomain": "superdesk",
      "tenant_uuid": "8f6c1c9e-1d2b-4c35-9a53-0b8f4f3c2d11",
      "platform": {
        "id": 95,
        "code": "main",
        "name": "Main"
      },
      "account": {
        "id": 31455,
        "name": "Superdesk Inc",
        "billing_day": 16,
        "contacts": [
          {
            "id": 31059,
            "first_name": "Doug",
            "last_name": "Holes",
            "email": "doug@example.com"
          }
        ]
      }
    },
    "change": {
      "occurred_at": "2026-11-05T17:42:10.123456Z",
      "sequence": 42,
      "credit_balance_id": 812,
      "feature": {
        "id": 77,
        "code": "api_calls",
        "name": "API call"
      },
      "currency_id": null,
      "previous_state": "blocked",
      "state": "ok",
      "previous_balance": 0.0,
      "balance": 100.0,
      "subscription": {
        "id": 31782,
        "state": "active"
      }
    }
  }
}

Change fieldsLink to Change fields section

Field Description
occurred_at When the change happened.
sequence Goes up as credits are added or used. Use it to ignore a webhook that arrives after a newer one.
credit_balance_id The credit balance that changed.
feature, currency_id What the balance holds: units of a feature (feature is set) or money (currency_id is set).
previous_state, state The balance’s state before and after the change.
previous_balance, balance The balance before and after the change. It includes credits granted with a later start date.
subscription The subscription the balance belongs to.

How to use the credit balance changed webhookLink to How to use the credit balance changed webhook section

Use tenant.code to find the tenant in your application, then:

  • Blocked: state is blocked. Stop usage for the feature in feature, or for all credit usage if the balance is in money.
  • Unblocked: previous_state is blocked and state is not. Allow usage again.
  • Credits added or used: compare balance with previous_balance.

Webhooks can arrive out of order when a delivery is retried. Store the last sequence you handled for each credit_balance_id, and ignore a webhook with a lower sequence. If two webhooks have the same sequence, the one with the later occurred_at is newer.

We expect your webhook endpoint to return a HTTP 200 response.