jkudish/laravel-ai-pricing
A Laravel package for calculating and tracking AI model costs. Define pricing for providers like OpenAI and Anthropic in config, estimate token-based expenses per request, and keep cost logic centralized so you can bill users, monitor spend, or compare models.
Install the package and publish its config/catalog, then confirm which pricing snapshot is active. v0.4.2 ships snapshot v19 (retrieved 2026-10-19), so the first check after upgrading is that your application is resolving snapshot v19 and not a cached older catalog.
The first practical use case is quoting or metering DeepSeek V4.1 Flash 1017. Look first at two places:
For day-to-day use, request the explicit qualified basis:
openrouter:deepseek/deepseek-v4.1-flash-1017-standard-max
Do not start with the generic openrouter:deepseek/deepseek-v4.1-flash-1017 identity if you expect it to resolve through a live catalog or Portkey headline price. That path is now blocked by design. Configure the generic identity explicitly if your application needs it.
Validate the integration with a single cost calculation against the qualified basis and assert the snapshot version alongside the result. Once that works, wire the lookup into your existing usage/billing flow.
Treat model identity and pricing basis as separate concepts. The model is deepseek/deepseek-v4.1-flash-20261017; the billable basis is openrouter:deepseek/deepseek-v4.1-flash-1017-standard-max. Keep the qualified basis in a constant, enum, or config mapping rather than scattering the raw string through jobs and controllers.
Centralize cost resolution behind one service. A small application-level service or action should accept a model key, token counts, and optional route/endpoint metadata, then resolve the basis, apply rates, and return a cost object. This is where you can handle fallback-blocked identities consistently instead of letting each call site deal with exceptions or nulls.
Use the -standard-max basis as a conservative pre-flight estimate. Because it is the maximum over the 13 default-routed endpoints, including quantization and time-of-day overrides, it is suitable for budgets, guardrails, and user-facing estimates that should not under-quote. For post-hoc reconciliation, pair it with actual provider invoices or recorded usage rather than presenting the estimate as exact.
Persist the snapshot version with cost records. Store snapshot=v19 (and the basis string) next to calculated costs. When rates change on endpoint churn, you can explain historical numbers without re-deriving them from a catalog that has moved.
Handle fallback-blocked identities explicitly. In your resolver, distingush between “unknown model” and “known but fallback-blocked identity.” The latter should fail fast with a clear application exception or be mapped through an explicit configured alias. Avoid silently returning zero cost, which is the most dangerous failure mode for billing and quota enforcement.
Use the qualified basis in tests and fixtures. Freeze the snapshot in test setup and assert that the generic identity is rejected while the qualified basis resolves. Add a regression test that the computed rates match the expected input, output, and cached-input values from snapshot v19.
Aggregate reporting by basis, not only by model. If you later add another basis for the same model, grouping solely by model will blend incompatible price points. Include the basis string in usage records and group by both.
-standard-max basis when its conditions are met, or configure the generic identity explicitly.openrouter:deepseek/deepseek-v4.1-flash-1017-standard-max as another name for the generic identity. It is a distinct, fallback-blocked basis with its own published rates.standard-max is a ceiling, not your expected bill. It is the maximum across all 13 default-routed endpoints, including every quantization and time-of-day override. Actual routed cost can be lower. Label estimates accordingly.relace and inference-net/fp8. If your traffic does not route through those endpoints, cached input will cost more than the headline maximum suggests. Do not apply the cached-input rate globally.How can I help you explore Laravel packages today?