boriskwemo / llm-ledger
Framework-agnostic PHP package to call and track costs of LLMs (OpenAI, Anthropic, Google, Mistral, DeepSeek, Qwen and more) with a unified API, a bundled model registry, and Symfony 8 / Laravel integrations.
Requires
- php: >=8.2
- ext-json: *
- ext-pdo: *
- nyholm/psr7: ^1.8
- psr/http-client: ^1.0
- psr/http-factory: ^1.0
- psr/http-message: ^1.1 || ^2.0
- symfony/http-client: ^6.4 || ^7.0 || ^8.0
- symfony/yaml: ^6.4 || ^7.0 || ^8.0
Requires (Dev)
- phpunit/phpunit: ^10.5 || ^11.0
Suggests
- illuminate/database: Required to persist usage via Eloquent in Laravel.
- illuminate/support: Required to use the Laravel integration.
- symfony/framework-bundle: Required to use the Symfony bundle integration (with symfony/twig-bundle and twig/twig for the dashboard).
- twig/twig: Renders the Symfony dashboard templates.
Provides
None
Conflicts
None
Replaces
None
README
Track and control LLM spend from one PHP API. Call OpenAI, Anthropic, Google Gemini, Mistral, DeepSeek, Qwen, Kimi, GLM, Grok and any OpenAI-compatible endpoint, with automatic cost and usage tracking baked in.
use LlmCostTracker\Client\Llm; $llm = Llm::fromYaml('llm.yaml'); $result = $llm->chat('deepseek-chat', 'Explain quantum computing in one sentence.'); echo $result->text(); // the answer echo $result->usage->totalTokens; // 42 echo $result->usage->reasoningTokens; // hidden thinking tokens, exposed echo $result->cost->total; // 0.000123 USD
Every call is recorded and shown in a dashboard: cost per model, provider and day, plus thinking tokens and response previews.
Install
composer require boriskwemo/llm-ledger
Requires PHP 8.2+ with ext-json and ext-pdo.
Configure
Create llm.yaml:
providers: openai: { api_key: env(OPENAI_API_KEY) } deepseek: { api_key: env(DEEPSEEK_API_KEY) } # ...anthropic, google, mistral, qwen, xai and more tracking: enabled: true storage: sqlite://llm.db
That's it. Drop in your keys and go.
Why LLM Ledger?
- One API for 19 providers - OpenAI, Anthropic, Google, xAI, Mistral, DeepSeek, Qwen, Kimi, GLM and any OpenAI-compatible server (vLLM, LiteLLM, local).
- Costs you can't miss - reasoning tokens, cached input and per-call USD are normalized and stored, not just the end-of-month bill.
- Built-in dashboard + CLI - a themed admin UI (light/dark, fully responsive) plus
llm-trackerfor the terminal. - Deprecation-aware model registry - a YAML catalog marks retired models and their replacements before they break you.
- Batch processing - one
batch()call across OpenAI, Anthropic and Gemini. - Symfony 8 + Laravel - an idiomatic bundle and service provider, not a raw HTTP client.
- Secure by default - API keys live in memory only; never persisted or logged.
Quickstart
require 'vendor/autoload.php'; use LlmCostTracker\Client\Llm; $llm = Llm::fromYaml('llm.yaml'); $result = $llm->chat('gpt-5.2', 'Hello!', ['tags' => ['demo']]); echo $result->text(); printf("cost: $%.6f\n", $result->cost->total); $totals = $llm->tracker()->totals(); // lifetime aggregates
Symfony 8
// config/bundles.php LlmCostTracker\Symfony\LlmCostTrackerBundle::class => ['all' => true],
# config/routes/llm_cost_tracker.yaml llm_cost_tracker: resource: '@LlmCostTrackerBundle/Resources/config/routes.yaml' prefix: /llm
public function __construct(private \LlmCostTracker\Client\Llm $llm) {} $answer = $this->llm->complete('mistral-large-latest', 'Hello!');
Dashboard at /llm, model catalog at /llm/models.
Laravel
php artisan vendor:publish --provider="LlmCostTracker\Laravel\LlmCostTrackerServiceProvider"
php artisan migrate
use Llm; $answer = Llm::complete('qwen3-max', 'Hello!');
Dashboard at /llm.
CLI
vendor/bin/llm-tracker models:list
vendor/bin/llm-tracker usage:report --days=30
vendor/bin/llm-tracker call deepseek-chat "Hello!"
More
- Model registry:
config/models.yaml. Pricing is a bundled snapshot; override it in your own YAML. - Standalone dashboard:
examples/dashboard.php(no framework required).
License
MIT. See LICENSE. Contributions welcome - CONTRIBUTING.md; report vulnerabilities per SECURITY.md.