$0.00. These are different problems with different causes.
Nothing is arriving at all
Export all three variables in the same process that runs your agent:attach() reads VOICEGW_COLLECTOR_URL and VOICEGW_API_KEY at call time. If either name is misspelled, nothing is sent and nothing raises: the sink is best-effort by design, so it buffers, fails, and retries quietly rather than taking your agent down over a telemetry problem.
That silence is deliberate, and it means a missing row is never reported as an error. Check the variable names first.
See the hosted quickstart for the full setup.
Rows arrive but every cost is $0.00
A $0.00 row is a real row. Four different things produce one, and they are not distinguished by the cost column, which is why the cost column is the wrong place to look:
pricing_source is what tells them apart. An empty pricing_source means VoiceGateway priced nothing because it did not recognise the model, and it logs a warning when that happens: No pricing data for <modality> model '<model>'; cost recorded as $0.
voice-prices-unrated is the subtle one. Some catalogue entries match a model and carry no rate at all: deepgram/nova-general matches the entry nova, whose price fields are all empty. The lookup succeeds, no rate is applied, and the total is zero. That zero is not a price, so the row is tagged voice-prices-unrated rather than voice-prices@<version> and logs matched the catalog but it carries no rate for <units>. The remedy differs from an unknown model: the entry exists already and needs a rate, rather than needing to be added.
The tag makes no claim about why there is no rate. A deliberately free tier and a missing rate are identical in the catalogue data, so VoiceGateway reports what it observed instead of guessing which one you have.
Self-hosted models are not a defect. They run on hardware you already pay for, and VoiceGateway records the usage without inventing a price for it.
An unrecognised model usually means one of two things. Either your collector is pinned to an older voice-prices than your agent, so a model your agent knows is one the collector has never heard of, or the model genuinely has no catalogue entry yet. Check the collector’s pricing_source version before assuming the second.
A row with no model at all
Rows with an emptymodel_id and modality eou are end-of-utterance timing records. No provider call happened, so no model and no cost is the correct answer rather than a gap. They carry their measurements in metadata.eou.
Use billable_requests rather than requests when dividing cost by a call count: requests counts every stored row, including these and failed calls, and a cost per call built on it reads low.
See cost tracking for how request costs are calculated.