# Plans, Usage & Billing

> How BillDog meters your account, what the free ceiling does to your SDK, and where the controls that actually change your bill live.

Source: https://billdog.io/docs/billing

---

## Overview

BillDog bills three products independently. An account can hold one plan in each, and each produces its own invoice lines on its own schedule:

- **Engagement Suite** — analytics, messaging, surveys and auth. Metered on usage.

- **Paywalls Suite** — a commission on monthly tracked revenue (MTR).

- **CortX AI** — a monthly subscription that also discounts parts of your Engagement bill.

**The single most useful thing to know:** `/dashboard/billing` is a reporting screen apart from its Group Analytics switch. Plan, card, spend limit, prepaid credit, invoice download and cancellation all live under **Profile Settings → Billing**. If you are looking for a button and cannot find it, you are on the wrong page.

## Engagement Suite plans

Two plans are available to sign up for:

| Plan | Base | Behaviour past the included allowance |
| --- | --- | --- |
| Free | $0 | Nothing is charged, ever — the invoice is clamped to zero. Instead, requests are refused once an allowance is exhausted. See the next section. |
| Pay-as-you-go | $0 | Larger allowances, and usage beyond them is billed at the per-unit rates on the [pricing page](/pricing). |

**Free never produces a bill.** Overage is computed and then discarded, so any per-unit rate you see quoted against Free is not something you can be charged. The consequence is the opposite of a bill: your traffic stops.

## What is metered

Counted daily and closed monthly. MAU is deduplicated across the whole account; most other meters are account totals rather than per-project.

| Meter | Unit | Worth knowing |
| --- | --- | --- |
| Monthly active users (MAU) | distinct person per month | Deduplicated across every project on the account. Split for reporting into anonymous, identified and authenticated — but today the authenticated rate matches the identified one. |
| Events | per 1,000 | Anonymous and identified events are counted separately and priced separately. |
| Push, in-app | per send | Push counts device fan-out, not messages: one notification to a person with three devices is three. |
| Email | per send | Bring-your-own-provider sends are not charged; managed sends are. |
| SMS | carrier cost + markup | Managed sends pass through carrier rates plus a percentage. Bring-your-own is not charged. |
| Survey responses | per response | Every survey response counts the same. There is no separate Smart AI survey meter. |
| Webhook attempts | per attempt | Attempts, not deliveries — a retried webhook counts each time. |
| Retention window | days | How far back your analytics history reaches, set by your plan. Stored data is billed per GB as a Data retention overage line. |

**Group Analytics is billed account-wide from a per-project switch.** Turning it on for one project meters identified events across *every* project on the account. Turning it off for that project changes nothing if another project still has it on.

## The Free ceiling, and what your app actually sees

On the Free plan each allowance is a hard stop rather than a charge. Seven endpoints refuse work once their meter is exhausted: event ingest, push sends, email sends, in-app message triggers, survey submissions, experiment events and attribution links.

The refusal is an HTTP 200 whose body names the exhausted meter; the data is not stored:

200 response

```
{
  "success": true,
  "quota_limited": ["in_app"],
  "quota": { "scope": "plan", "metric": "in_app", "cap": 25000 },
  "message": "Your free plan's monthly in_app allowance (25,000) is exhausted — this data was not stored. Add a payment method / upgrade your Engagement plan to keep sending."
}
```

**The web, iOS and Android SDKs do not surface this, and the events are lost.** Because the refusal is a 200, those analytics SDKs treat it as a successful upload: they drop the batch from their queue, keep flushing on schedule and show no warning. The server SDKs (Node, Python, Go and the rest) read `quota_limited`, warn once and pause capture, probing again every 15 minutes. Contrast a 429 from the project rate limit, which is persisted and retried with backoff. So hitting the rate limit costs you nothing, and hitting the free ceiling costs you every event until you add a card or the month resets.

**Adding a payment method removes the ceiling immediately.** The quota check passes as soon as a card is on file, so traffic resumes without a plan change — and while you remain on Free the invoice is still clamped to zero.

## Spend limits

**Profile Settings → Billing → Spend limits.** Set a monthly cap in USD, and BillDog emails you at 80% and 100%. With enforcement on, it also pauses processing.

### What a limit does and does not stop

A spend limit throttles cost traffic only. It pauses event ingest, push, email and SMS sends, in-app impression tracking, survey submissions, experiment events, attribution, session-replay uploads and error ingest.

It never stops a purchase, an entitlement check, a customer-info lookup, a paywall fetch or an API-key check. Your app keeps selling and keeps unlocking what people have paid for, though BillDog Auth codes sent by email or SMS pause like any other send. The suspension response says so:

402 response

```
{
  "success": false,
  "error": {
    "code": "BILLING_LIMIT_REACHED",
    "message": "Usage paused: your monthly spend limit has been reached. Purchases and entitlements are unaffected. Raise or remove the limit in billing settings to resume."
  },
  "meta": { "request_id": "…", "api_version": "…", "timestamp": "…" }
}
```

Only the Engagement Suite scope can enforce. Paywalls and total-account limits are alert-only by design, and the database refuses to store them any other way.

### Four things that surprise people

- **Both toggles are required.** A limit needs *Enforce* and *Enabled*. Saving a dollar figure with neither on produces a limit that does not alert and does not enforce — and still shows a success toast.

- **You cannot clear a limit by emptying the field.** A blank value is rejected by the database and the save fails. Turn *Enabled* off instead.

- **It is evaluated once a day, not live.** Up to about 24 hours of spend can land past the cap. Raising the limit, or turning Enforce or Enabled off, resumes traffic as soon as you save.

- **It triggers on a forecast, not on spend to date.** Usage so far is extrapolated to a full-month run rate and that projection is compared to your cap, so a burst early in the month can pause an account that would never have reached the limit.

**Nothing in the dashboard tells you that you are suspended.** The enforcement state is not surfaced anywhere in the UI. If ingest has gone quiet and your allowances are not exhausted, check your spend limit before you check your integration.

## Invoices, credits and payment

Your real invoices — with their numbers, payment status, PDFs and usage CSVs — are under **Profile Settings → Billing → Invoices**. Prepaid credit is bought from the same tab, and drawn down against charges automatically.

**The invoice tables on `/dashboard/billing` are not those invoices.** They are the computed usage lines behind them, and every row carries a permanent “Pending Stripe push” badge that does not describe your payment status. Use the Invoices card in Profile Settings for anything you need to pay, reconcile or file.

## Reading the billing dashboard

`/dashboard/billing` shows current-period usage, a period history and the computed Paywalls invoice lines; its Engagement tab stays empty. Three things about it are worth knowing before you reconcile anything against it.

1. **The Engagement tab never lists a line.** It reads “No invoices generated yet” on every account. Your Engagement invoice is account-wide, with MAU deduplicated across every project, and appears only under Profile Settings → Billing → Invoices. The usage cards at the top cover the selected project alone.

2. **Period labels can read one month early.** Periods are stored at UTC midnight and rendered in your local timezone, so west of UTC a period beginning 1 August displays as July.

3. **Only the account owner sees the real plan.** A team member on the same project sees the page claim the free tier and no payment banners, though the usage cards and Paywalls lines are real, with no error to explain it.

## Where each task actually lives

| Task | Where |
| --- | --- |
| Change plan | Profile Settings → Billing → Engagement Suite Plan → Update Tier |
| Add or replace a card | Profile Settings → Billing → Payment Methods |
| Set a spend limit | Profile Settings → Billing → Spend limits |
| Download an invoice or usage CSV | Profile Settings → Billing → Invoices |
| Buy prepaid credit | Profile Settings → Billing, or Prepay on the billing dashboard |
| Cancel | Profile Settings → Billing → Cancel subscription |
| See usage and computed lines | `/dashboard/billing` |

## Related

- [Pricing](/pricing) — current rates and allowances

- [Product Analytics](/docs/product-analytics) — what generates events

- [Group Analytics](/docs/group-analytics) — the account-wide meter

- [Troubleshooting](/docs/troubleshooting)
