Worked pricing samples
The generated blocks below document every parameter and response shape; this overlay walks the three chains a tenant actually runs before a send decision: estimate one destination → read the effective rate sheet → replay traffic against a candidate rate card (the what-if call every sender runs before committing volume), read the current rate card → audit a rate change → explain the delta on a bill, and the operator-level SMS rate card with scope filters team admins use to compare organizations. Every response is the real{ data, meta } envelope — data carries the payload, meta
carries the request_id and timestamp. Quote meta.request_id when you
report a bad number.
The Node SDK does not wrap the pricing namespace yet (/pricing/rates in the
SDK targets the legacy per-country table, not these tenant routes), so the
typed tabs below use the SDK’s orbit.request escape hatch — you get the
SDK’s auth, retries, and envelope unwrapping against the raw REST path.
Python fronts client.request the same way.
1. Estimate one destination before you send
GET /api/v1/pricing/estimate resolves a single send to the per-unit rate
the wallet would actually be charged. Pass channel and a destination to
in E.164 form — the endpoint resolves the destination country itself. Add
allIn=true to stack the hidden-fee line items (US A2P 10DLC registration,
call recording, transcription, premium support) a “what does this lane
really cost” question needs; include narrows that list to named surcharge
codes.
200
2. Verify against your effective rate sheet
GET /api/v1/pricing/effective-rates is the tenant-facing read the what-if
and estimate checks reconcile against: the global platform card collapsed
with any per-org overrides down to the single row the billing resolver would
charge per (channel, sub-type, country, direction) lane. Each row shows the
bare base rate and the effective per-unit price in cents after overrides
(and, for SMS, the platform default markup) are layered on — so the number
you display cannot drift from the number the wallet debits. hasCustomRate
is set only when your own org carried the override, never for the platform
default.
200
3. Replay traffic against a candidate rate card (the what-if)
POST /api/v1/pricing/whatif-simulate is the call you run before committing
volume: it replays a window of your own observed traffic (one entry per
billable lane, in usage) against a candidate rate card
(candidateRates) and projects the cost side-by-side with what the traffic
was actually billed. Traffic is held fixed; only the rate card is swapped —
that is the what-if. It is read-only: nothing is written, nothing is sent,
and an INSUFFICIENT_BALANCE at send time later means the top-up reminder
was never a reason to skip this preview. Both arrays fill a real body — a
bare {} returns 422.
200
"unmatched": true and
"matchedRatePerUnit": null — read unmatchedLaneCount before you trust
totalProjectedUsd; a candidate card with coverage gaps under-projects.
4. Read the current rate card (admin)
GET /api/v1/pricing/rates is the super-admin read of the full platform
rate card — every lane, global defaults and per-org rows alike, ordered by
channel then country. Use it before you edit or retire a lane; the list is
capped at 5,000 rows.
200
5. Audit what a rate change did to a tenant’s bill
GET /api/v1/pricing/changelog answers “when did my pricing change, and
what changed”. A super-admin sees the raw internal audit rows (actor,
reason, before/after snapshots) and may filter by organizationId; a tenant
API key gets the sanitized projection — which surface changed
(rate_card or org_override), the action, whether it was a global
rate-card change or org-scoped, and the timestamp — with the internal
fields stripped, and scope pinned to the caller’s own org plus global
changes. A tenant-supplied organizationId is ignored (no cross-tenant
read). Cap with limit (default 100, max 500).
200
changedBy, a
free-text reason, and the full beforeState / afterState snapshots —
shape preserved verbatim, internal fields included. Pair the tenant view
with /pricing/effective-rates to explain a line on a bill; pair the
super-admin view with /pricing/overrides?organizationId=... to scope the
audit to one tenant.
6. Operator-level SMS rate card with scope filters
GET /api/v1/pricing/mccmnc-rates is the customer-facing SMS rate card at
mobile-operator (MCCMNC) granularity, with your organization’s markup
already applied. Filter with search (operator name, country, or MCCMNC
code) and country, and page with cursor / limit. A row with no
published cost returns "your_rate": null — the “Contact sales” row — and
pricing_source attributes each row to the same rule the send-path resolver
bills under (override / org_markup / default_markup), so the preview
cannot quote a price the wallet would not charge.
200
/pricing/organizations (org rows with a hasCustomRates flag, all=true
for one round trip) and /pricing/overrides?organizationId=org_... — let a
team admin compare a tenant’s negotiated rates against the platform card
before answering a dispute.
7. Public price list (no key needed)
GET /api/v1/public/pricing publishes the platform pay-as-you-go price list
with the pricing-model manifest — one tier, no contact-sales gate, no forced
migrations. It is unauthenticated and IP rate-limited, so a prospect can
verify pricing before signing up. Pass ?country=US for the published
country-specific list; omit it for the baseline.
200
per_segment), not per message: a GSM-7
body splits every 160 characters and a UCS-2 (unicode) body every 70, so a
long send costs N× the per-segment rate. Voice bills per minute, fax per
page. Bring-your-own-credential channels (WhatsApp, Instagram, Messenger,
push, Apple Messages, LINE) are listed with "billed": false at $0 — the
platform only charges for what it terminates itself.
8. Errors worth branching on
The envelope mechanics —error.code / message / status / details,
retry order, retriable-vs-terminal — live once in the
error-handling guide.
Here is what the branch decision on THIS page comes down to.
Treat
422 and 403 as terminal, not retriable — a corrected request fixes
the first; the second needs a super-admin key or a switch to the
tenant-facing read. 429 and 401 are retry-once-after-fix and
re-key-then-retry respectively. The pricing reads draw from the same
RATE_LIMIT_AUTH_WRITE bucket as the other authenticated reads, and the
public list has its own IP bucket — the envelope’s
error.details.retry_after says how long.
These samples compound; the auto-generated per-operation entries below
always carry the full parameter table even where a sample here already
covers the op.