Inbound cost metering
Outbound sends and inbound traffic run through the same pricing engine but live on different planes: a send resolves a price and debits your wallet in the same breath, while received traffic is priced and reported without ever touching the wallet. This page is the model for that second plane — whatGET /api/v1/usage/inbound-cost reports, why it can never move money, and
what to reconcile it against.
1. A reporting plane, not a metering plane
Spend tracking in Orbit grew up outbound-first. Every send resolves a charge through the shared rate-resolution step and writes it through the wallet ledger, so the usage and billing dashboards always knew what you spent sending. Received traffic never got the same treatment: SMS and MMS that arrive on your numbers, and voice minutes that terminate to them, are billed by carriers per message and per minute — but nothing priced that volume, so any “total spend” view you built silently excluded it. The inbound-cost report closes that gap by reading what already happened instead of metering as it happens:- Outbound meters. The send path writes one usage record and debits the wallet synchronously — the loop described on the usage metering pipeline.
- Inbound reports. The report aggregates the volume your tenant
already persisted — received messages from the
messagestable and received calls fromcall_logs— and prices that volume on demand for the window you ask for. Nothing is written and nothing is charged; the figure you get is a read of recorded volume at current rates.
2. The response contract
One request covers one window and answers with one total plus one line per channel that carried received traffic:periodlabels the window (aYYYY-MMcalendar month by default).range.from/range.toare the exact half-open interval the lines aggregate, so two reports can always be compared by interval.currencyis the ISO-4217 code of your wallet currency — the same currency every other billing surface reports in, so this figure can never disagree with your balance about which currency it speaks.lines[]carries one entry per channel with received volume: thechannel(sms,mms,voice), the billingunit(next section), thequantityin that unit, the per-unitunit_price_cents, the line totalcost_cents, and thepricing_sourceattribution (section 4). Lines are ordered most-expensive first.
total_cost_cents is
the exact sum of the per-line cost_cents values, and there is no sub-cent
drift between the breakdown and the total. Per-unit prices may carry
sub-cent precision (0.8 above); each line rounds to whole cents once, and
the total adds those rounded lines.
The window itself is chosen with a calendar month, a rolling window, or an
explicit from/to pair — the same options as the rest of usage reporting;
the API reference carries the full parameter contract.
3. The two billing units received traffic uses
Inbound traffic bills on exactly two units:per_message— received SMS and MMS. Each received message counts as one, exactly as the carrier bills termination. There is no segment arithmetic here: SMS segments and encoding can multiply the cost of a long outbound message because the platform pays per segment, but a received message is a single billable event regardless of its length or encoding.per_minute— inbound voice. Each received call rounds up to the next whole minute (a 61-second call bills as two minutes), mirroring how carriers bill termination;quantityis the sum of those rounded minutes over the window.
4. The same resolution chokepoint, with direction “mo”
Pricing a received message uses the same rate-resolution step as pricing a send —resolvePrice(), the chokepoint documented on
pricing and rate resolution — with the
direction set to "mo" (mobile-originated / inbound) and the country
wildcarded to *, which resolves the global inbound rate for the channel.
The report also shares the batched ladder read (resolveBaseRatesBatch()):
every channel’s rate shape resolves in one pass instead of one lookup per
line, and org markup overrides still apply per channel exactly as they do
for sends.
Because both passages share the ladder, each line’s pricing_source names
the rung that produced its unit price, using the same attribution labels
as outbound rating:
org_markup— the base inbound rate marked up by your organization’s own override.default_markup— the base inbound rate with the platform-default markup.fallback— no inbound rate row matched the channel yet, so the per-channel fallback price was used; the report therefore works before per-country inbound rate sheets exist.absolute_override— an absolute per-unit price set for your organization, verbatim.
5. Reporting-only invariants
Three guarantees define the plane:- It never mutates the wallet. No debit row, no credit deduction, no authorize/capture hold — a report request cannot change your balance.
- It never calls a provider. The report is a pure read of persisted volume plus the rate ladder.
- It reconciles to deliverables, not to ledger rows. You will not
find a wallet transaction matching an inbound line, because none
exists — this is the explicit contrast with
the wallet ledger audit trail,
where every outbound debit is a row you can point at. To reconcile an
inbound line, re-derive it: filter your received messages and calls to
the same
range, count messages and carrier-rounded minutes, and multiply by the line’sunit_price_cents.
6. Where this page sits in the billing family
- The usage metering pipeline — the outbound loop. Its aggregation stage already counts inbound rows (its counter rollups name “sms-inbound, sms-outbound” alongside voice), but stops at counts; this page is the cost side of those inbound counts.
- Pricing and rate resolution — the precedence ladder both directions resolve through, and the home of the attribution labels.
- Wallets, credits, and charges — the append-only ledger the inbound plane deliberately never writes.
7. Where to see it live
- Dashboard. The Billing → Usage page shows received-traffic cost next to your outbound spend.
- API.
GET /api/v1/usage/inbound-costreturns the report for your tenant. - Guide. Inbound traffic cost metering walks worked endpoint calls and reads a breakdown end to end.