Skip to main content

Rate cards

The subaccounts guide prices a child either on the flat reseller_margin_pct or on an inline rate deck (per-channel/destination markup cells). Both approaches inline the pricing on the child itself. A rate card is the next step up: a named, re-usable price book you draft once on your parent organization and assign to any number of subaccounts — the same pricing, draftable once and never re-entered, survives deployments and re-provisioning. Full endpoint catalog: Subaccounts API.

What a rate card is

A rate card is a named pricing template your parent org keeps in a library. Each card carries a stable id (rc_...), a human label, and one or both of the two cell families:
  • Lane cells — candidate per-lane rates captured from the what-if pricing preview (POST /billing/whatif-pricing/preview), kept verbatim. A lane is a channel/country/direction pair, such as “WhatsApp to Nigeria.”
  • Deck cells — channel[, destination] → margin_pct markup cells, the same shape an inline rate deck uses.
Both families are optional; a card with neither a lane cell nor a deck cell is dropped by the validator as noise. Parents may keep up to 50 cards; each card carries up to the same cell count an inline deck accepts.

Rate-card lifecycle: create, version, persist, assign

The library lives on the parent org. You replace it full-set with PUT /api/v1/subaccounts/rate-cards and read it with GET /api/v1/subaccounts/rate-cards. To version a card, PUT the full library again with the updated entry — the validator dedupes by id (last write wins), sorts by name, and returns the normalized library it actually stored, so the response is always the source of truth. Because the PUT is full-set, the workflow for versioning is: GET the library, edit one card in the array, PUT the whole array back. An empty array clears the library. Margin in a deck cell is a markup percent over your wholesale cost — the same margin_pct semantics as the inline rate deck (0–100%). Draft it in one place and reuse it for every subaccount on that plan tier.

Assignment

Point a subaccount at a saved card once:
The parent’s library is the single source of truth: you can only assign a card that still exists in the library — assigning an orphan id returns 400 BAD_REQUEST. To un-assign, send rate_card_id: null and the child falls back to its flat margin or its own inline deck. Read the current assignment back on GET /api/v1/subaccounts/{id}/rate-deck, whose response carries both the inline deck and the assigned_rate_card_id so the dashboard shows which named card the child prices against.

How resolution picks the card

At send time the pricing-rate-resolution precedence applies: when a subaccount has an assigned rate card, the card’s cells supply the markup; when it does not, the child’s own inline rate deck applies; when neither exists, every usage line prices on the flat reseller_margin_pct. The assignment is a pointer, not a copy — update the card in the parent’s library and every assigned child resolves against the new cells on its next send.

Example: a WhatsApp card with a 5% margin

Create the card in the parent library:
Assign it to a subaccount:
From that point, WhatsApp-to-Nigeria and WhatsApp-to-Ghana sends on sub_acme price at wholesale + 5%, and the parent’s reseller statement reports the marked-up price against the wholesale cost. The subaccount’s own admin never sees your wholesale side — the margin lands in your statement, not their dashboard.