openai_cost/lib.rs
1//! # openai-cost
2//!
3//! Calculate OpenAI API call cost from a usage block.
4//!
5//! OpenAI returns three token counts on a chat-completion or responses-API
6//! response: `prompt_tokens` (a.k.a. `input_tokens`), `completion_tokens`
7//! (a.k.a. `output_tokens`), and `prompt_tokens_details.cached_tokens`
8//! (a.k.a. `cached_input_tokens` on the Responses API). Each has its own
9//! price. This crate gives you a small `Pricing` table for popular models
10//! and a `Usage` struct that knows how to compute cost from those fields.
11//!
12//! Pricing is best-effort and dated; verify against
13//! <https://openai.com/api/pricing/> before using these numbers for
14//! billing.
15//!
16//! ## Quick example
17//!
18//! ```
19//! use openai_cost::{Usage, default_pricing};
20//!
21//! let pricing = default_pricing("gpt-5").unwrap();
22//! let usage = Usage {
23//! input_tokens: 1_000,
24//! output_tokens: 500,
25//! cached_input_tokens: 0,
26//! };
27//! let cost = pricing.cost_for(&usage);
28//! // 1k * input + 500 * output, divided by 1M
29//! assert!(cost > 0.0);
30//! ```
31//!
32//! ## Versioned model ids
33//!
34//! ```
35//! use openai_cost::default_pricing;
36//! // The crate normalizes dated suffixes (`gpt-5-2026-04-01`) back to
37//! // the base model name.
38//! assert!(default_pricing("gpt-5-2026-04-01").is_some());
39//! ```
40//!
41//! ## BYO pricing
42//!
43//! ```
44//! use openai_cost::{Pricing, Usage};
45//! let custom = Pricing {
46//! input_per_mtok: 1.25,
47//! output_per_mtok: 5.0,
48//! cached_input_per_mtok: 0.125,
49//! };
50//! let usage = Usage::default();
51//! let _ = custom.cost_for(&usage);
52//! ```
53
54#![deny(missing_docs)]
55
56mod normalize;
57mod pricing;
58mod usage;
59
60pub use normalize::normalize_model_id;
61pub use pricing::{default_pricing, Pricing, DEFAULT_PRICING_TABLE};
62pub use usage::Usage;