Skip to content

Billing & Monetization

Most platforms let you pay them. Axowl billing points the other way: your organization charges its own end users, through the same identity core that authenticates them.

Three structural properties set it apart:

  1. Per-app-group collection. Each app group (brand) runs its own plans and charges its own users under its own name. One organization, many collecting brands.
  2. Consolidated statements. Every brand rolls up into one organization-level statement — the whole company in one book.
  3. Sealed invoices. A period statement is sealed the moment it closes. Every line traces back to the ledger entry it billed, and anyone can verify the seal independently — see Invoices and Seals & integrity.

Money settles to your own Stripe account. Axowl takes a rate — it never holds your funds.

One rate on billed volume. No per-invoice fee, no monthly minimum. Stripe processing passes through at cost.

PlanTake rateApp groups that collectVolume capConsolidated + verify API
Free0.7%1$5,000 / month
Pro0.7%1No cap
Pro+0.6%UnlimitedNo cap
Business0.5%UnlimitedNo cap
Enterprisefrom 0.4%UnlimitedNo cap

Numbers in this table are rendered from PricingConstants.Monetization on the live pricing page — if the two ever disagree, the constants win.

Design decisions worth knowing:

  • Free is metered by volume, not by features. The full engine — plans, seats, usage, sealed invoices — works on Free. Past the cap, new charges pause until you upgrade; existing subscriptions keep collecting.
  • Sealing is not gated. Every invoice on every plan is sealed — that is how the product works. Business gates the organization roll-up, the public verify API, and audit export.
  • Downgrades never cut a live subscription. Dropping below a plan blocks new collection that the lower plan wouldn’t allow; charges already running are grace-period protected.

Each app group has a collection switch: Dashboard → Applications → your app group → Payments → “Billing collection”. Turning it on is plan-gated — how many app groups may collect at once comes from the schedule above (Free/Pro: 1, Pro+ and up: unlimited). Past the limit the server answers 403 { "error": "UPGRADE_REQUIRED", "feature": "billing.collect" }. Turning it off is always allowed, and a downgrade never flips the switch on a group that is already collecting — only new enables are blocked.

Every flip is a sealed audit event: appgroup.monetization.enabled / appgroup.monetization.disabled.

Turning collection on or off is billing, so it follows the owner carve-out: the organization owner, or a member explicitly granted view.billing, may flip it. Editing the app group itself is not enough — an admin without that grant gets 403 PERMISSION_DENIED.

Collection lands in your organization’s cash account on the settlement ledger, one line per sale. Because those lines are keyed by the brand that sold, the org-level total needs its own call:

GET /api/org/{slug}/billing/earnings
{
"configured": true,
"cashBalance": 1985.40,
"brands": [ { "brand": "acme-cloud", "cashBalance": 1985.40, "lines": 42 } ]
}

This is the opposite direction from /billing/credit, which is what your organization pays Axowl. Cash and credit are separate books by design — this endpoint only ever reports settled money. Owner-only, same gate as the switch.

Payment engines read the org’s billing policy before charging on its behalf — Axowl publishes the policy; the engine executes it.

GET /api/public/v1/monetization
X-Api-Key: ah_live_…
{
"takeRatePercent": 0.7,
"currency": "USD",
"perInvoiceFixedFeeUsd": 0,
"monthlyVolumeCapUsd": 5000,
"collectingAppGroups": { "limit": 1, "enabled": 1 },
"consolidatedEnabled": false,
"appGroups": [ { "id": "", "name": "", "monetizationEnabled": true } ]
}

monthlyVolumeCapUsd is null on paid plans; collectingAppGroups.limit of -1 means unlimited. Unknown or missing plans resolve fail-closed to the Free rules.

A payment engine that holds a brand→org binding rather than the org’s own key asks by org id instead — same response shape:

POST /api/public/v1/orgs/monetization
X-Api-Key: ah_live_…
Content-Type: application/json
{ "orgId": "" }

Anyone holding an invoice id can verify the sealed statement — no API key, no Axowl account:

GET /api/public/v1/invoices/{id}/verify

The endpoint recomputes the statement hash from the stored lines and compares it to the value sealed at issue time. It returns the verdict and both hashes — never amounts (it is an anonymous surface). Statements still open for the current period report "status": "open" and seal when the period closes. Available when the issuing org is on the Business plan or higher; below that the endpoint answers 403 UPGRADE_REQUIRED.

How the rate is collected — ✅ built (engine side)

Section titled “How the rate is collected — ✅ built (engine side)”

Settlement runs on Stripe Connect. When a consumer pays for a catalog product, the charge routes to the brand’s connected account as a destination charge, and the take rate is withheld at the source as a Stripe Connect application fee — never billed separately, and never debited from your Axowl credit ledger (cash and credit are separate books by design). The engine reads this page’s policy API at charge time; if the policy cannot be read, the charge is refused rather than guessed. Past the Free volume cap, new charges are refused with upgrade_required — running subscriptions are unaffected.

  • Invoices — the sealed period statement itself.
  • Seals & integrity — what a seal proves and how to verify one.
  • Public API — where the pricing and verify endpoints live as they ship.