The columns
Header names are matched case-insensitively and ignoring punctuation, so input_tokens and inputTokens are the same column. Every spelling in the “also accepted” list below is read directly from the parser.
timestamprequiredISO 8601, or epoch seconds, or epoch milliseconds. A zone-less ISO value is read as UTC.When the call happened. Drives windowing and regime detection. An ambiguous slash date (MM/DD versus DD/MM) is rejected as a row error rather than guessed.
also accepted: created · createdat · date · requestcreatedat · starttime · timestamp · ts
modelrequiredThe provider model id exactly as you log it — gpt-4o, claude-sonnet-5, anthropic/claude-sonnet-5. Blank is a row error.
also accepted: model · modelname
input_tokensrequiredwhole tokens, zero or moreUncached prompt tokens. If you also send cache_read_tokens, the engine adds them back to get the true prompt size — so this column is the uncached portion only.
also accepted: inputtokens · prompttokens · tokensprompt
output_tokensrequiredwhole tokens, zero or moreCompletion tokens.
also accepted: completiontokens · outputtokens · tokenscompletion
applicationoptionalThe subsystem or feature the call belongs to. This becomes a node in your architecture graph. Rows with no value are attributed to a single 'unattributed' application rather than dropped.
also accepted: app · application · applicationname · appname · userapikeyalias
cache_read_tokensoptionalwhole tokens, zero or more; absent means 0Tokens served from a cached prefix. A call counts as a cache hit when this is above zero.
also accepted: cachedtokens · cachereadinputtokens · cachereadtokens
cache_write_tokensoptionalwhole tokens, zero or more; absent means 0Tokens written into the cache.
also accepted: cachecreationinputtokens · cachewritetokens
cost_usdoptionalUS dollars as a decimal number — not cents, not eurosWhat the call cost, if your export carries it. Absent means Bayeto estimates it from the pinned model catalog and says so on screen.
also accepted: calculatedtotalcost · cost · costusd · responsecost · spend · totalcost · usage
latency_msoptionalMILLISECONDS. Fractions are rounded.End-to-end call latency. Read the units twice: an export whose latency column is in seconds will be read as milliseconds, because nothing can safely tell 4.2 seconds from 4.2 milliseconds.
also accepted: durationms · latency · latencyms
provideroptionalWho served the call. When present it is treated as a logged fact rather than an inference, which is what lets the provider-arbitrage rule speak with more confidence.
also accepted: customllmprovider · litellmprovider · provider · providername
regionoptionalWhere the call was served, if you know. Without it the cross-region rule stands down instead of guessing.
statusoptionalPer-call outcome, stored exactly as written. Classified at read time: a numeric status uses HTTP semantics, a known failure word counts as a failure, and anything absent or unrecognised counts as a success.
What the schema refuses
Anything not in the list above is never read, so there is nothing to strip later. That covers prompt and completion text, user and session identifiers, emails, trace ids, API keys, and request or response bodies — a column with one of those names is skipped before its value is touched.
Three refusals are deliberate enough to name. A value that is not a simple number or string is ignored even under an accepted column name, so a nested usage object from an OpenAI export cannot become a cost. LiteLLM’s bare user field is not accepted as an application name, because it may carry an end-user identifier. And nothing about your prompts is inferred from what is present: the schema has no place to put content, by design.
Web uploads are parsed in your browser. The file never leaves your machine; only normalized rows matching the table above are transmitted, and the server re-validates them with the same rules.
Two units that bite
Cost is US dollars, as a decimal number. Not cents, not euros. Bayeto displays euros and converts at a pinned rate it states on screen.
Latency is milliseconds. Some exports label a seconds column with the same name. Nothing can safely tell 4.2 seconds from 4.2 milliseconds, so the parser does not try — it reads what the column says it is. If your latency numbers look impossibly small on screen, that is the reason.
Rows the parser rejects
A row missing any required field, carrying a non-numeric token count, or dated ambiguously (03/04/2026 could be March or April) is reported as a row error and not ingested. A malformed row never becomes half-ingested. Ambiguous dates are rejected rather than guessed, because a guess would move traffic between days and quietly change every window in the analysis.
This describes the upload path. The live LiteLLM connector is a separate entrance with its own mapping and its own handling of bad events; if you are streaming rather than uploading, its behaviour is documented with the connector.