Billing
Cowliss has two plans, Free and Plus. Every feature (automations, custom sending domains, segments) is on both from the first event: a plan decides only how much usage is included each month and how many apps and sending domains an org may hold. Spend past the included usage draws a prepaid wallet, and nothing is ever billed in arrears.
| Free | Plus | |
|---|---|---|
| Price | $0 | $9.99 a month |
| Included usage, each UTC month | $0.50 | $15 |
| Live apps | 1 | 15 |
| Sending domains | 1 | 10 |
- Plus is a monthly subscription. An org admin starts it from Settings → Billing in the dashboard and pays by card; the CLI and MCP server never start one. The Plus fee never touches the wallet.
- Cancelling happens on the same page, at any time. Plus stays on until the end of the month already paid for, then the org is on Free. A failed renewal does not end it straight away: Plus stays on while the card is retried, and ends only once the payment is given up on.
- Limits are checked when you create an app or a sending domain, and only then. An archived app frees its slot; a sending domain holds one from the moment you add it, verified or not, until you delete it. A create past the limit answers 403
plan_limit, its message naming the limit and the way up. - Over the limit after cancelling: an org that left Plus with more apps or sending domains than Free allows keeps every one of them, and they keep working. Creating another is refused until the org is back under the limit.
Organizations a partner runs
Section titled “Organizations a partner runs”An organization a partner created on a customer’s behalf is billed by that partner, not here: the partner sets the plan over the API (its choice wins over any subscription), may let usage run past the included amount (counted as overageMicros on the billing summary, never refused and never charged to a wallet), and the top-up and subscription routes answer 409 partner_managed. Included usage and the limits per plan are the same.
The model
Section titled “The model”- Included usage: every org gets its plan’s included usage ($0.50 on Free, $15 on Plus) each UTC calendar month, spent before the wallet. Unused included usage does not roll over.
- Wallet: spend past the included usage draws a prepaid balance, funded by fixed-amount one-time payments ($10 / $50 / $200) through Stripe Checkout. Wallet credit that is not spent carries over month to month and never expires. When a month closes, what it spent past its included usage leaves the wallet for good; a top-up raises the balance, and a refunded payment or a lost chargeback lowers it.
- Remaining credit =
max(0, included usage + balance − spend). At zero, the platform hard-stops: ingestion answers 429over_quotawithRetry-After, and email/webhook sends recordskipped_quotain the delivery log. Nothing is ever billed in arrears: there is no overage invoice, because nothing can run past zero. - Warning: from 80% of credit used, the dashboard shows a top-up banner, so a rejection never surprises you.
- Refunds and chargebacks: a refunded payment or a lost chargeback takes its amount back out of the wallet, as a separate line in the transactions table beside the payment it answers. That can leave the balance below zero; once nothing is left, it is the same hard stop, and a top-up brings it back up and starts sending again. Nothing is invoiced, and no usage already delivered is clawed back.
What usage costs
Section titled “What usage costs”Usage is one weighted spend across four metered actions, computed in integer micro-dollars (1,000,000 per dollar: no float ever touches money):
| Action | Rate |
|---|---|
| Event ingested | $2 per 10,000 |
| Email sent | $4 per 10,000 |
| Webhook delivered | $2 per 10,000 |
| Automation run | $2 per 10,000 |
What counts, and what does not:
- Events are customer-written rows, including batch backfill. System events Cowliss writes itself (
system.segment_entered,system.segment_exited,system.consent_revoked, delivery feedback) are never metered. - Sends count when settled;
failed, skipped (skipped_*), and dry-run (would_*) deliveries are excluded by construction. - Automation runs count real instances, and each
restartstep counts as one run; dry runs cost nothing. - A price of 0 would make an action free without removing it from the meter: the catalog is one map in
packages/shared, tweakable in one place.
Spend is counted, never incremented: every number is a count of records that already exist (your events, the delivery log, automation executions), so the meter can never drift from the thing it bills for, and a replayed webhook or a re-run backfill cannot double-charge.
Topping up
Section titled “Topping up”POST /v1/billing/topups { amountMicros: 10_000_000 } (a preset, not free-form) → 201 { checkoutUrl } (Stripe-hosted Checkout)… pay on Stripe …Stripe webhook checkout.session.completed → wallet credited, ledger row completedThe wallet is credited by the webhook and nowhere else: the topup endpoint answers only a checkout URL, and the ledger row it writes stays pending until Stripe confirms. The wallet_topups ledger is the audit trail of every top-up and its state.
Reading usage
Section titled “Reading usage”- Dashboard: Settings → Billing shows balance, this month’s spend against included usage, remaining credit, and top-up history.
- API:
GET /v1/billingreturns the included usage (allowanceMicros), wallet balance, period bounds, spend, remaining credit withwarn/overflags, the usage counts, and the price catalog that weighted them. - CLI:
cow billingprints the same summary.
The hard stop is the same everywhere
Section titled “The hard stop is the same everywhere”One creditMicros function in packages/shared computes remaining credit for the API’s 429 on ingestion, the worker’s skipped_quota send gate, the billing page, and the dashboard banner: four surfaces, one arithmetic. A runaway automation hits the same wall as a runaway import: no bug can burn unbounded volume or credit.