# Billing concepts

> Plans and features, seats, the prepaid wallet and top-ups, metered usage, invoices and dunning, and Nexafon's fee on paid WhatsApp orders.

Source: https://docs.nexafone.so/v1/billing/

Each workspace (each partner store, too) is billed on its own. Billing screens work inside `<nexafon-app>` for users
with `billing:manage`; others see that they lack access. Prices and limits always come from Nexafon’s server: an
integration sends ids and quantities, never amounts.

## Plans and features

A plan grants **features**: on/off switches, limits and metered items. Operations declare the feature they need
(`x-feature` in the [API reference](/v1/api/)); without it they answer `feature_not_in_plan`, and above a limit
`plan_limit_reached`. `GET /api/v1/me/access` tells the embedded screens what the workspace has.

| Feature | Kind | What it covers |
| --- | --- | --- |
| `call_recording` | boolean | Record calls |
| `calls.max_participants` | limit (participant) | People in one call |
| `calls.priority_ring` | boolean | Priority ring strategy |
| `commerce.catalog` | boolean | Store product catalog |
| `commerce.orders` | boolean | Store orders |
| `commerce.payments` | boolean | Store customer payments |
| `commerce.products.max` | limit (product) | Products in the store catalog |
| `ivr.depth` | limit (level) | Nested IVR menus |
| `meetings.max_minutes` | limit (minute) | Length of one scheduled meeting |
| `meetings.voice` | boolean | Scheduled voice meetings |
| `recordings.library` | limit (recording) | Recordings in the call audio library |
| `recordings.retention_days` | limit (day) | Recording retention |
| `sdk.embeds` | boolean | SDK embeds and custom domain |
| `seats` | limit (seat) | Staff seats; viewers do not use one |
| `sso.workspace` | boolean | Workspace SSO (Microsoft or Google) |
| `storage.bytes` | metered (byte) | Stored files: WhatsApp media, recordings, prompts, invoices and exports |
| `whatsapp.number` | limit (number) | One business WhatsApp number per workspace |
| `workspace.core` | boolean | The workspace itself; every workspace always has it and no plan can take it away |

## Seats

Each member with a paid role takes one **seat** (viewers do not). A plan includes some seats; more are added as a
seat add-on, quoted and prorated by the server. When every seat is taken, inviting or adding a member answers
`seat_limit_reached`, and a partner user token for that store answers `no_free_seat`, unless the owner turned on
**add seats automatically**: then a seat is bought from the wallet in the same step (or refused with
`insufficient_balance` when the wallet cannot pay). Fewer seats take effect at renewal.

## Wallet

Usage is paid from the workspace’s **wallet**:

- **Prepaid** (the default): top up first; paid actions stop when the balance cannot cover them
  (`insufficient_balance`), while replies inside WhatsApp’s 24-hour window and incoming calls keep working.
- **Postpaid** (approved by Nexafon): usage counts against a credit limit (`credit_limit_reached`) and is invoiced
  monthly.

Store owners top up with mobile money through PayPoint from the billing screen: choose the wallet and number, enter
the PIN on the phone, and the balance updates live once PayPoint confirms. When the balance falls below its alert
threshold the owner is notified and a `billing.low_balance` webhook goes out; auto top-up can refill it.

## Usage

Metered usage is charged to the wallet as it happens, at the workspace’s rate card:

- paid WhatsApp templates (marketing and utility messages outside the 24-hour window);
- business-initiated WhatsApp calls, per minute;
- stored files beyond the plan’s allowance.

## Invoices and dunning

Subscriptions renew monthly and are invoiced (`invoice.created`, `invoice.paid` webhooks). An unpaid invoice goes
through reminders, then **past due** (paid templates and outbound calls pause: `billing_past_due`), then the workspace
becomes read-only (`workspace_read_only`) until it is paid. Each step sends a `billing.dunning` webhook.

## Order fees

Nexafon charges a fee on each **paid** WhatsApp order. The sale money goes to the store’s PayPoint account, so the fee
is charged to the store’s **wallet**:

- It is computed on the goods after discounts, **without delivery**: `fee = round_half_up(goods × percent) + fixed`,
  then kept between the rule’s minimum and maximum. Integer cents throughout.
- The rule is the store’s plan’s fee rule, else Nexafon’s default; the rule in force when the order is paid applies.
- It is booked once per order, within a second of payment, and shows as “Fee on order #N” in the wallet history.
- A prepaid fee is booked even if it takes the balance below zero; postpaid fees appear on the monthly invoice.
- Refunding or cancelling a paid order does not reverse its fee.

Example: $27.00 of goods and $1.00 delivery at 1.5% books one fee of $0.41 (2700 × 1.5% = 40.5 cents, rounded up).
