> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Rate cards: persisted price books you assign to subaccounts

> Name, version, and persist a reseller rate card once — then assign it to a subaccount so it prices against that card across every deployment, with the margin resolved at send time.

# Rate cards

The [subaccounts guide](/guides/subaccounts-reseller) 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](/api-reference/subaccounts).

## 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](#assignment) 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:

```bash theme={null}
curl -X PUT https://api.orbit.devotel.io/api/v1/subaccounts/sub_abc123/assigned-rate-card \
  -H "X-API-Key: dv_live_sk_your_parent_key" \
  -H "Content-Type: application/json" \
  -d '{ "rate_card_id": "rc_whatsapp_west_africa" }'
```

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](/concepts/pricing-rate-resolution) 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:

```bash theme={null}
curl -X PUT https://api.orbit.devotel.io/api/v1/subaccounts/rate-cards \
  -H "X-API-Key: dv_live_sk_your_parent_key" \
  -H "Content-Type: application/json" \
  -d '{
    "cards": [
      {
        "id": "rc_whatsapp_west_africa",
        "name": "WhatsApp West Africa Q3",
        "deck_cells": [
          { "channel": "whatsapp", "destination": "NG", "margin_pct": 5 },
          { "channel": "whatsapp", "destination": "GH", "margin_pct": 5 }
        ]
      }
    ]
  }'
```

Assign it to a subaccount:

```bash theme={null}
curl -X PUT https://api.orbit.devotel.io/api/v1/subaccounts/sub_acme/assigned-rate-card \
  -H "X-API-Key: dv_live_sk_your_parent_key" \
  -H "Content-Type: application/json" \
  -d '{ "rate_card_id": "rc_whatsapp_west_africa" }'
```

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.

## Related pages

* [White-label subaccounts](/guides/subaccounts-reseller) — provision, brand, and fund children; the flat margin and inline deck the rate card builds on.
* [Pricing and rate resolution](/concepts/pricing-rate-resolution) — the per-operator precedence the assigned card feeds into.
* [Wallet currency conversion](/billing/wallet-currency-conversion) — how converted top-ups interact with the wallet a subaccount draws down.
* [Per-channel connection mode: BYO vs platform default](/guides/subaccount-connection-modes) — the connection your subaccounts' sends exit on, independent of how the rate card prices them.
* [Subaccounts API](/api-reference/subaccounts) — full endpoint schemas for the card library and assignment routes.
