Search by

jkudish / laravel-ai-pricing

jkudish

Shared, provenance-aware AI pricing and cost attribution for Laravel applications.

Package info

github.com/jkudish/laravel-ai-pricing

pkg:composer/jkudish/laravel-ai-pricing

Fund package maintenance!

jkudish

Statistics

Installs: 931

Dependents: 2

Suggesters: 0

Stars: 1

Open Issues: 0

v0.4.1 2026-10-14 05:13 UTC

README

Trustworthy AI cost attribution for Laravel.

Tests Quality License

Laravel AI Pricing tells you what an AI request cost, or what a future request is expected to cost. Use it after a Laravel AI response with cost(). Use quote() before a request when you need an estimate for a budget, model picker, or guardrail.

Installation

Install the package with Composer:

composer require jkudish/laravel-ai-pricing

Laravel discovers the service provider automatically. You do not need to publish the configuration to get started.

Costing Laravel AI responses

Call AiPricing::cost() after an agent has completed its request:

use Jkudish\LaravelAiPricing\Facades\AiPricing;

$response = (new ReceiptOcrAgent)->prompt($prompt);

$cost = AiPricing::cost($response);

$cost->amount;       // Brick\Math\BigDecimal, or null
$cost->currency;     // "USD", or null
$cost->source;       // Where the amount came from
$cost->completeness; // complete, partial, or unavailable

cost() reads the response's public provider, model, and usage data. It then returns a CostQuote.

If $cost->amount is null, the package did not have enough compatible pricing information. It does not return 0 for an unknown cost.

What does “cost” mean?

A cost result is either provider-reported or calculated:

Result Meaning
provider_reported The provider returned a monetary amount with the response. This is the closest thing to an invoice amount.
configured Your application supplied the model's rates in config/ai-pricing.php.
provider_native or portkey The package multiplied the response's billable usage by a published price from a remote catalog.
unavailable No compatible price was found.

Most providers return token counts, not dollars. For those responses, Laravel AI Pricing calculates an amount from the token usage and a price list. That calculated result is useful for application accounting, budgets, and reporting. It is not a replacement for a provider invoice.

Reasoning tokens

OpenAI, Anthropic, Gemini, and OpenRouter all bill reasoning as part of the output count. The package prices the output family as a single partition, never as additive units, and expects the reported output_tokens count to be inclusive of reasoning.

A reasoning_tokens rate is the price for reasoning tokens and replaces the output rate for them:

  • omitting the rate means the output rate applies (the whole inclusive output_tokens count bills at the output rate, so an incomplete catalog can never bill reasoning twice);
  • 0 means reasoning is free — a deliberate claim, not "no extra charge".

When a rate is published, the family prices as (output_tokens - reasoning_tokens) x output rate + reasoning_tokens x reasoning rate. A zero OpenRouter internal_reasoning price means the model bills reasoning inside its completion price, so it is not mapped to a rate at all and reasoning settles at the output rate.

Catalogs written under the pre-0.2 additive semantics that used a 0 reasoning rate to mean "no extra charge" must remove that rate when upgrading, or their reasoning tokens will bill at $0.

One dialect reports the output count exclusive of reasoning: the laravel/ai 0.x Gemini and xAI drivers kept the thought or reasoning count outside the completion count (the 1.0 SDK folds it into the output total itself). The adapter folds those payloads by default. Payloads from any other source whose output count excludes reasoning can declare that with the same payload key the input semantic uses:

$cost = AiPricing::cost([
    ...$response->toArray(),
    'reasoning_token_semantic' => 'exclusive',
]);

Omitting the semantic bills the payload as inclusive unless it is a 0.x Gemini or xAI observation. A Usage object constructed directly must carry reasoning-inclusive output_tokens; adjust the count yourself before constructing it if your source reports reasoning separately.

Price catalogs

A price catalog is a list of published rates for provider models. A rate says how much one unit costs, such as one million input tokens or one million output tokens.

When a response has usage but no provider-reported amount, the package looks up the response's provider and model in a catalog, then calculates:

cost = input usage × input rate + output usage × output rate

The package checks prices in this order:

  1. A provider-reported cost attached to the response.
  2. A price configured by your application.
  3. Provider-native pricing attached to the observation.
  4. OpenRouter's public model catalog for OpenRouter models, unless the package snapshot fallback-blocks the identity.
  5. The package's reviewed pricing snapshot.
  6. Portkey's public provider catalog as a fallback.
  7. An unavailable result.

The first compatible price wins. An identity the package snapshot fallback-blocks skips both remote catalogs, OpenRouter's and Portkey's, so only a provider-reported cost, a configured price, observation-native pricing or the snapshot itself can price it. The package does not convert currencies. A USD result only uses USD pricing.

The OpenRouter catalog only prices what a model lookup can apply. A model whose catalog entry lists pricing overrides (prompt-length or time-of-day tiers) is not priced from its base tier, and the Portkey fallback is skipped for it too, so it resolves to unavailable unless you configure a price or the snapshot has a basis for it. A catalog that publishes a 1-hour cache-write rate prices cache_write_input_tokens_5m and cache_write_input_tokens_1h instead of the aggregate. Google cache writes stay unpriced. Documented audio and image-token fields require token counts; ambiguous image and image_output fields remain unmapped. See modality-specific usage before quoting multimodal models.

Built-in API product SKUs

Non-model APIs use a documented pricing SKU in the existing model field. The package includes a reviewed, versioned USD snapshot for products that do not publish a suitable machine-readable runtime catalog:

The snapshot-level retrieved_at records when the package snapshot was assembled. Individual notes retain an earlier per-SKU source review date when an unchanged entry was carried forward.

Provider SKU Usage units
brave answers queries, input_tokens, output_tokens
brave search requests
dataforseo chatgpt-llm-scraper-standard, chatgpt-llm-scraper-live requests
dataforseo gemini-llm-scraper-standard, gemini-llm-scraper-live requests
dataforseo google-ai-mode-standard, google-ai-mode-live requests
exa search requests, additional_results, summary_pages
exa research agent_compute_units, searches
kagi fastgpt uncached_queries
you answer requests
you research-lite, research-standard, research-deep, research-exhaustive requests
perplexity agent-low, agent-medium, agent-high web_searches, fetch_url_requests, people_searches, finance_searches, sandbox_sessions, sandbox_searches
perplexity search requests
parallel turbo requests, additional_results
parallel research-lite, research-base, research-core, research-core2x, research-pro, research-ultra, research-ultra2x, research-ultra4x, research-ultra8x processor_requests
valyu research-fast, research-standard, research-heavy, research-max research_requests, screenshot_urls, code_executions, additional_deliverables
typesafe jev-1.13.0 (aliases jev-latest, jev-preview) input_tokens, output_tokens (free)
subq subq-snap-preview input_tokens, output_tokens (free)
xai grok-4.7, grok-4.6 searches, x_search_posts, x_search_profiles

The Exa request rate includes up to ten results; pass only results above ten as additional_results. Pass uncached_queries: 0 for a free cached Kagi response. You.com Frontier Research has negotiated usage and is intentionally unavailable.

The PHP v2 parity profiles use these pricing identities and dispositions:

Provider/profile Pricing identity Disposition
brave-search/search brave:search Built-in fixed request rate.
tavily/search tavily:search Configured-only: USD per credit depends on the account plan; Basic uses one credit and Advanced uses two.
perplexity-search/search perplexity:search Built-in fixed rate per successful request.
perplexity-deep-research/research (medium) perplexity:agent-medium Built-in stable tool rates only; routed model usage remains partial or unavailable.
jina-search/search jina:search Unavailable: Jina publishes token consumption without a stable public USD conversion.
serpapi/search serpapi:search Configured-only: rates and speed multipliers depend on the account plan.
serpbase/search serpbase:search Configured-only: use the account's actual price per credit, not a public headline minimum.
serpbase/news serpbase:news Configured-only: use the account's actual price per credit, not a public headline minimum.
exa/research exa:research Built-in Auto-effort ACU and search rates; fixed efforts and enrichment require their applicable rates.
gemini-deep/research gemini:deep-research Unavailable: model, intermediate token, and tool quantities are provider-controlled.
grok, grok-x-only/x, grok-combined/combined xai:grok-4.7 (or xai:grok-4.6 for the previous model) Built-in current Web Search and per-item X Search rates only; context-tiered model tokens remain partial or unavailable.
parallel/search parallel:search Configured-only: the selectable mode and additional-result count determine the price.
parallel/turbo parallel:turbo Built-in fixed Turbo request and additional-result rates.
parallel/research parallel:research-{processor} Built-in fixed rate per successful run for every listed processor, lite through ultra8x.
valyu/search valyu:search Unavailable: every result can use a differently priced source class.
valyu/research valyu:research-{mode} Built-in Fast, Standard, Heavy and Max base and optional-tool rates; provider-reported response cost is preferred.
firecrawl-search/search firecrawl:search Configured-only: the API uses fixed credits, but USD per credit depends on the account plan.

Configured-only and unavailable identities are recorded as fallback-blocked policy, not zero-value price entries. This prevents a coincidentally named Portkey model from supplying an incompatible price, while still allowing provider-reported actual cost or an explicitly configured application rate. Configure the exact identity and account rate when you can prove its applicability.

The DataForSEO SKU names identify products and modes; they are not assertions about the underlying model. For these SKUs, requests: 1 means one restricted billable task/result-page submission. A normal-priority Standard submission is billed once and its later retrieval GETs are free, so do not count those GETs as additional requests. The built-in prices cover only the base normal Standard and Live operations reviewed from DataForSEO's official pages on 2026-09-06. They exclude high-priority, bulk, HTML, rectangle, and other surcharged options. LLM Scraper pricing does not apply to LLM Responses.

These prices are estimates, not invoices. Provider-reported actual cost still wins, failures may be charged, and missing usage produces an unavailable result rather than a zero quote. This package supplies pricing identities only; it does not implement DataForSEO task submission, polling, or retrieval.

Perplexity Agent presets route across models and tools, so the preset SKUs contain only stable tool rates. A quote with tool usage and unpriced routed-model units is partial; model-only usage is unavailable. Prefer the completed response's provider-reported usage.cost.total_cost whenever present. The package does not treat representative preset runs as fixed prices or maximums.

Parallel Turbo includes ten results; pass only results above ten as additional_results. Exa Research's built-in rates apply to Auto effort (agent_compute_units plus searches). Valyu Standard Research must include optional tool units when used. The xAI entries intentionally omit model-token rates because Grok 4.7 and Grok 4.6 bill a higher tier once a prompt reaches 200,000 tokens (≥ 200k) and US regional requests bill at 1.1x. Their search-tool rates were reviewed against docs.x.ai/developers/pricing on 2026-09-26 (Grok 4.6) and 2026-10-11 (Grok 4.7): Web Search bills USD 5 per 1,000 calls (searches), while X Search has billed per item fetched since the 2026-09-21 change — USD 5 per 1,000 posts returned by a search or thread fetch, including parent and quoted posts (x_search_posts), and USD 10 per 1,000 profiles returned by a user search (x_search_profiles). Map the reported usage.server_side_tool_usage_details fields onto these units: web_search_calls to searches, x_posts_fetched to x_search_posts, and x_users_fetched to x_search_profiles. Never map the x_search_calls count onto the per-item units: it counts tool calls, not fetched items, and xAI no longer bills X Search per call. searches is preserved as the Web Search call unit, and its meaning has narrowed accordingly: callers that previously passed X Search calls as searches must migrate to x_search_posts and x_search_profiles, or their quotes no longer match xAI's per-item billing. Because the reviewed snapshot precedes the Portkey fallback, these partial xAI entries deliberately prevent incompatible flat fallback token rates from being applied to grok-4.7 or grok-4.6; token-only usage is unavailable, and search plus token usage is partial.

TypeSafe Jev prices laravel/ai ClassificationResponse objects directly: AiPricing::cost($response) reads the typesafe provider, the versioned model the API reported (for example jev-1.13.0), and the input and output token counts. The reviewed rate is USD 0.042 per million input tokens from docs.typesafe.ai/models (checked 2026-09-28). TypeSafe documents output tokens as free, so the entry publishes an explicit zero output_tokens rate and the reported output count keeps a quote complete instead of partial. The snapshot's source-local aliases map lets quote('typesafe', 'jev-latest', ...) use the rate of the version the alias currently points to while keeping jev-latest as the quoted identity. Aliases move when TypeSafe ships a new release; any versioned model the snapshot has not reviewed, such as a future jev-1.14.0, stays unavailable until its rate is added.

The reviewed Jev snapshot takes precedence over Portkey. On 2026-10-13, Portkey's TypeSafe catalog published 4.2e-08 for input, which becomes USD 0.00042/M under its cents-per-token contract, 100 times below TypeSafe's official rate. The package preserves the catalog's decimal and unit contract; it does not apply a provider-specific correction. Use the reviewed snapshot or a verified configured price for Jev.

SubQ's public Decisions preview uses subq:subq-snap-preview, at USD 0.05 per million input tokens with free output, checked against its model documentation on 2026-10-13. The early-access subq-preview chat model has no published price and stays unavailable. Decisions pricing does not apply to the chat model.

SearchAPI charges successful searches at an account-plan-specific rate, so searchapi:search is unavailable by default. Configure the successful_search_request unit with your account rate before enforcing a budget. For example, if your account charges USD 4 per 1,000 successful requests:

'prices' => [
    'searchapi:search' => [
        'successful_search_request' => [
            'amount' => '4', // Replace with your account plan's rate.
            'per' => '1000',
            'currency' => 'USD',
        ],
    ],
],

After configuration, the resolver returns a Complete configured quote. A Google AI Overview workflow that makes two successful SearchAPI requests must pass successful_search_request: 2.

SerpBase Search and News are also unavailable by default. Configure each identity with the account's current credits rate before using a hard budget:

'prices' => [
    'serpbase:search' => [
        'credits' => ['amount' => '0.00047', 'currency' => 'USD'],
    ],
    'serpbase:news' => [
        'credits' => ['amount' => '0.00047', 'currency' => 'USD'],
    ],
],

The example amount is illustrative only. Do not derive either configured rate from a public minimum; use the effective price for the consuming account.

Built-in model billing bases

Some model prices depend on facts the model name does not carry: inference geography, service tier, prompt length, or the API endpoint. The snapshot publishes those prices as qualified billing bases. A billing basis is a pricing identity that names the conditions its rates apply to. It is not a provider model ID or an alias of one.

Provider Billing basis Applies only when Usage units
anthropic claude-opus-5-5-global-standard Global geography, standard speed, synchronous Messages API input_tokens, output_tokens, cached_input_tokens, cache_write_input_tokens_5m, cache_write_input_tokens_1h
anthropic claude-sonnet-5-5-global-standard Global geography, synchronous Messages API Same as Opus 5.5, plus web_searches (USD 10 per 1,000 searches)
anthropic claude-haiku-5-5-global-short, claude-haiku-5-5-global-long Global geography, synchronous Messages API; prompts up to 100,000 tokens (-short) or above (-long), counting cache reads and writes Same as Opus 5.5
openai gpt-6.1-sol-standard-short, gpt-6.1-sol-standard-long Direct API, standard service tier; up to 272,000 input tokens (-short) or above (-long) input_tokens, output_tokens, cached_input_tokens, cache_write_input_tokens, web_searches (USD 10 per 1,000 search calls; pass the count, because OpenAI usage does not report it)
openai gpt-6-luna-standard-short, gpt-6-luna-standard-long Direct generation API, standard service tier; same 272,000-token threshold Same as GPT-6.1 Sol, including web_searches
openai decisions-gpt-6-luna-short, decisions-gpt-6-luna-long POST /v1/decisions (public beta) with GPT-6 Luna; same 272,000-token threshold input_tokens; output and cache units are published as explicit zero rates
zai glm-5.3, glm-5.3-flash Direct Z.AI pay-as-you-go API, not the Coding Plan or OpenRouter input_tokens, cached_input_tokens, output_tokens
deepseek deepseek-v4-pro-peak Direct API, priced at the peak rate as a conservative reservation; off-peak is half price input_tokens, cached_input_tokens, output_tokens
cloudflare @cf/cloudflare/clef, @cf/cloudflare/clef-flash (equivalent short selectors clef, clef-flash) Workers AI paid usage at USD 0.24/M and 0.038/M input tokens respectively; the shared daily free allowance is not subtracted per request input_tokens, output_tokens (free)
openrouter google/gemini-3.1-flash-lite-standard-max OpenRouter default routing at the standard service tier, priced at the most expensive default-routed endpoint (regional Vertex, 1.1x); never with flex or priority (service_tier, :floor, :nitro or tier-suffixed provider slugs) input_tokens, output_tokens, cached_input_tokens, web_searches (native Google Search grounding queries only)
anthropic claude-fable-5-1-global, claude-mythos-5-1-global, claude-fable-5-global, claude-mythos-5-global, claude-opus-4-7-global, claude-opus-4-6-global, claude-sonnet-5-global, claude-sonnet-4-6-global Global geography, synchronous Messages API Same as Opus 5.5, plus web_searches
anthropic claude-opus-5-global-standard, claude-opus-4-8-global-standard Global geography, standard speed, synchronous Messages API Same as Opus 5.5, plus web_searches
anthropic claude-opus-4-5-20251101, claude-haiku-4-5-20251001 (aliases claude-opus-4-5, claude-haiku-4-5) Synchronous Messages API; these models have one Claude API price Same as Opus 5.5, plus web_searches
gemini gemini-3.8-flash-standard, gemini-3.6-flash-standard Gemini Developer API, paid standard tier; dated rate windows switch from the introductory rates (0.75/M input, 3.75/M output) to the doubled rates (1.50/M, 7.50/M) at 2027-01-01T00:00Z input_tokens, output_tokens, cached_input_tokens, web_searches (Google Search grounding queries)
gemini gemini-3.8-flash-standard-2026/-2027, gemini-3.6-flash-standard-2026/-2027 The same prices as single-rate bases; -2026 for requests before 2027-01-01T00:00Z, -2027 from then Same as above
gemini gemini-4-argon-standard Gemini Developer API, paid standard tier, all prompt lengths; dated rate windows switch from the introductory rates (2/M input, 10/M output, 0.10/M cache hits) to the doubled rates (4/M, 20/M, 0.20/M) at 2026-12-01T00:00Z input_tokens, output_tokens, cached_input_tokens (implicit cache hits; explicit caching is unsupported), web_searches (Google Search grounding queries)
gemini gemini-3.5-flash-lite-standard, gemini-3.1-flash-lite-standard, gemini-3-flash-preview-standard Paid standard tier; Flash-Lite 3.1 and 3 Flash Preview exclude audio input Same as Gemini 3.8 Flash
gemini gemini-3.1-pro-preview-standard-short/-long, gemini-3.1-pro-preview-customtools-standard-short/-long Paid standard tier; prompts up to 200,000 tokens (-short) or above (-long), counting cached tokens Same as Gemini 3.8 Flash
gemini gemini-2.5-pro-standard-short/-long, gemini-2.5-flash-standard, gemini-2.5-flash-lite-standard Paid standard tier, no grounding; same 200,000-token threshold for Pro; Flash and Flash-Lite exclude audio input input_tokens, output_tokens, cached_input_tokens
openai gpt-6-astra-, gpt-6-sol-, gpt-5.6-sol-, gpt-5.6-terra-, gpt-5.6-luna-, gpt-5.5- and gpt-5.4-standard-short/-long Direct API, standard service tier; up to 272,000 input tokens (-short) or above (-long) Same as GPT-6.1 Sol, plus web_searches
openai gpt-5.5-pro-, gpt-5.4-pro-standard-short/-long, gpt-5.2-pro-standard Direct API, standard service tier input_tokens, output_tokens, web_searches
openai gpt-5.4-mini-standard, gpt-5.2-standard Direct API, standard service tier, all prompt lengths Same as GPT-6.1 Sol, plus web_searches
openai gpt-4.1-standard, gpt-4.1-mini-standard, gpt-4o-standard, gpt-4o-mini-standard, chat-latest-standard Direct API, standard service tier, no web search Same as GPT-6.1 Sol
deepseek deepseek-flash-peak, deepseek-flash-off-peak, deepseek-v4-pro-off-peak Direct API; peak as a conservative reservation, off-peak only for requests known to run off-peak input_tokens, cached_input_tokens, output_tokens
zai glm-5.3-flashx, glm-5.2, glm-5.1, glm-5, glm-4.7, glm-4.6, glm-4.5-air Direct Z.AI pay-as-you-go API input_tokens, cached_input_tokens, output_tokens
moonshot kimi-k3, kimi-k2.7-code, kimi-k2.7-code-highspeed, kimi-k2.6 Kimi international API (api.moonshot.ai, USD) input_tokens, cached_input_tokens, output_tokens; Kimi K3 adds cache_write_input_tokens_5m and _1h
meta muse-wonder-1.0 Meta Model API pay-as-you-go Standard mode, all prompt lengths; not Muse Wonder Full or Muse Code subscriptions input_tokens, cached_input_tokens, output_tokens (reasoning included), web_searches (USD 2.50 per 1,000 search queries; pass the count)
dashscope qwen3.8-max-intl, qwen3.8-flash-intl, qwen3.7-max-intl, and the tiered qwen3.7-plus-intl-*, qwen3.7-flash-intl-*, qwen3-max-intl-*, qwen-plus-intl-{thinking,nonthinking}-*, qwen-flash-intl-*, qwen3-coder-plus-intl-*, qwen3-coder-flash-intl-* Alibaba Model Studio, Singapore region, International deployment scope; the suffix names the request's input-token tier (-32k, -128k, -256k, -1m) input_tokens, cached_input_tokens (20% implicit-cache rate; unpriced for Qwen 3.8), cache_write_input_tokens, output_tokens
openrouter anthropic/claude-*-standard-max (13 bases, including Haiku 5.5 -standard-short-max/-standard-long-max at 100,000 prompt tokens) Default routing at the standard tier, priced at the regional 1.1x endpoints; never fast mode input_tokens, output_tokens, cached_input_tokens, cache_write_input_tokens_5m, cache_write_input_tokens_1h, web_searches
openrouter google/gemini-3.6-flash-standard-max-2026, google/gemini-3.5-flash-lite-standard-max, google/gemini-3.1-pro-preview[-customtools]-standard-short/-long Default routing at the standard tier; Pro split at 200,000 prompt tokens input_tokens, output_tokens, cached_input_tokens, web_searches
openrouter google/gemini-4-argon-standard Default routing at the standard tier (Google AI Studio and Vertex global only), never flex, priority or :batch. Expires at 2026-12-01T00:00Z, when Google doubles its rates; future OpenRouter rates must be reviewed separately input_tokens, output_tokens, cached_input_tokens, web_searches (native Google Search grounding queries only)
openrouter meta/muse-wonder-standard The single Meta endpoint at Meta's list rates input_tokens, cached_input_tokens, output_tokens, web_searches (native Meta search only)
openrouter openai/*-standard-max-short/-long and -standard-max (36 bases, including the -pro IDs) Default routing without flex, fast or ultrafast, priced at the regional 1.1x endpoints; -short below 272,000 prompt tokens input_tokens, output_tokens, cached_input_tokens, GPT-5.6 and later cache_write_input_tokens, reasoning models web_searches
openrouter deepseek/*, qwen/*, moonshotai/* and z-ai/*-standard-max (26 bases, including deepseek/deepseek-v4.1-flash-1017-standard-max) Default routing without opt-in tier endpoints, priced at the worst default-routed endpoint input_tokens, cached_input_tokens, output_tokens; some Qwen and Kimi bases add cache_write_input_tokens

Additional reviewed bases cover specialized endpoints:

Provider Billing basis Conditions and units
openai gpt-5.6-cyber-standard-short, gpt-5.5-cyber-standard Direct standard-tier Cyber; both bases require at most 272,000 prompt tokens, including cached tokens. Ordinary token units; cache writes priced only for 5.6.
openai gpt-rosalind-research-standard, gpt-rosalind-discovery-standard Direct standard-tier Rosalind. Research's reviewed rates start 2026-10-05T00:00Z; dates before that are unavailable. Ordinary token units.
openai gpt-image-2.5-{sunburst,flare}-standard-{responses,images} Choose the endpoint you used. Exclusive text input, image input, and image output token units; cached text/image units only for Responses.
openai gpt-live-1-session voice_session_seconds at USD 0.05 per 60 seconds. Backend usage is additional and unpriced.
openai gpt-realtime-2.1-standard, gpt-realtime-2.1-mini-standard Direct standard-tier realtime; exclusive text/audio/image input and cached-input tokens, text/audio output tokens.
openai gpt-realtime-translate-standard Duration-billed translation, audio_seconds at USD 0.034 per 60 seconds.
openai gpt-4o-transcribe-standard, gpt-4o-mini-transcribe-standard, gpt-4o-transcribe-diarize-standard Exclusive audio input and text output token units. Estimated per-minute costs are not fixed duration rates.
openai gpt-audio-1.5-standard-chat Standard Chat Completions only; exclusive text/audio input and output tokens. No cached-input rates.
gemini gemini-3.8-live-standard, gemini-3.8-live-extended-thinking-standard Paid standard Live API; exclusive text/audio/image/video input and text/audio output tokens.
gemini gemini-omni-1.1-flash-standard Paid standard Interactions API; exclusive input modalities, text output at USD 9/M and video_output_tokens at USD 17.50/M. The rounded per-second equivalent is not a duration rate.
gemini gemini-3.5-transcribe-standard, gemini-3.5-transcribe-live-standard Separate unary and Live endpoints; exclusive audio input and text output tokens. Estimated per-minute costs are not duration rates.
gemini gemini-3.5-live-translate-preview-standard Paid standard Live API; exclusive audio input and output tokens. Returned text transcripts remain unpriced.
gemini gemini-nano-banana-2.1-standard Paid standard API; exclusive text/image/video input and text/image output tokens. Image output bills tokens at USD 30/M, not image counts.
gemini gemini-embedding-2-standard Exclusive text/image/audio/video input tokens. PDF pages use image tokens.
gemini gemini-3.8-flash-tts-standard, gemini-3.8-flash-lite-tts-standard Exclusive text input and audio output tokens. Dated windows double the rates at 2027-01-01T00:00Z.
gemini gemini-robotics-er-2-preview-standard, gemini-robotics-er-2-streaming-preview-standard Paid standard preview. Dated windows double token rates at 2027-01-01T00:00Z; the non-streaming basis also prices cached input and cache_storage_token_hours.
gemini veo-3.1-generate-preview-standard-{720p,1080p,4k}-audio Successfully generated video with audio; billable_video_seconds at USD 0.40/second for 720p/1080p and 0.60/second for 4K.
gemini veo-3.1-fast-generate-preview-standard-{720p,1080p,4k}-audio Fast model variant, standard service; billable_video_seconds at USD 0.10, 0.12, and 0.30/second respectively.
gemini veo-3.1-lite-generate-preview-standard-{720p,1080p}-audio Lite model variant; billable_video_seconds at USD 0.05 and 0.08/second respectively. No 4K basis.
gemini lyria-3.5-standard-full-song Paid standard Interactions API; billable_songs at USD 0.08 per full song. Response blocks, lyrics, tokens, and duration do not establish a song count.
cloudflare @cf/cloudflare/clef-omni (equivalent short selector clef-omni) Workers AI retail paid usage, USD 0.15/M input tokens and free output; no per-request deduction of the shared free allowance.
openrouter google/gemini-3.8-flash-standard Reviewed global standard endpoint rates, not flex or priority. Expires at 2027-01-01T00:00Z; future OpenRouter rates must be reviewed separately. Cache writes remain unpriced.

An OpenAI model card's per-minute estimate does not establish duration billing. gpt-transcribe, gpt-live-transcribe, and gpt-realtime-whisper remain unavailable until exact billing rates and units can be verified. Likewise, OpenRouter's Nano Banana image-output field remains ambiguous and cannot supply a safe image quote.

Omni's pricing table includes audio input, while its model page lists text, image, and video input. The published audio rate does not assert additional model capability. Veo's caller must qualify the variant, resolution, audio setting, and successfully generated duration. An all-zero usage observation remains unavailable under the existing API contract; it does not establish a verified zero invoice.

Where a Gemini basis prices billable_web_searches, pass only queries that remain billable after your account's allowance. A raw search count does not establish that quantity. The snapshot entry's notes name the applicable allowance and exclusions.

openrouter:google/gemini-3.1-flash-lite-standard-max is a conservative bound basis, like the OpenRouter -272k bases. OpenRouter's default routing for Gemini 3.1 Flash Lite load-balances between Google AI Studio and Vertex global (USD 0.25/M input, 1.50/M output) and the regional Vertex us and eu endpoints (0.275/M and 1.65/M), so the generic model ID has no single rate. The basis bills every request at the regional rates, which can overstate a request served at the global rate by 10%. Cache writes are deliberately unpriced, because OpenRouter's catalog and its prompt-caching guide disagree on the Gemini cache-write price. A cache_write_input_tokens count therefore keeps the quote partial; implicit caching writes nothing. Map usage.server_tool_use.web_search_requests to web_searches only when the native engine ran: an auto request with domain filters falls back to Exa, which is a different, unpriced unit. The generic openrouter:google/gemini-3.1-flash-lite identity is fallback-blocked: the live OpenRouter catalog would price it at the AI Studio headline rate and a storage-only cache-write rate, so it resolves to unavailable unless you configure a price.

The package cannot see where or how a request ran, so the caller must enforce each basis's conditions and choose the basis that matches the request. Send Claude requests to global inference geography, send OpenAI requests on the standard tier, choose -short or -long from the request's actual prompt length, and use a Decisions basis only for the Decisions endpoint. A basis applied to a request that breaks its conditions produces a wrong number, not an unavailable one. Each entry's notes in resources/pricing/provider-skus.php lists what it excludes, such as US geography (1.1x), fast mode, batch, flex, regional processing uplifts and server tools.

The OpenRouter -standard-max bases are conservative bound bases too. Each prices every request at the most expensive endpoint OpenRouter's default routing can choose, so a request served by a cheaper endpoint is overstated. The open-lab bases take each rate from the worst default-routed endpoint, so they can exceed any single endpoint. Endpoint sets change often; re-review a basis when its endpoints churn. For a completed OpenRouter request, prefer the provider-reported usage.cost.

Snapshot v18 fallback-blocks gemini:gemini-4-argon, openrouter:google/gemini-4-argon and openrouter:meta/muse-wonder. Quote gemini:gemini-4-argon-standard, openrouter:google/gemini-4-argon-standard or openrouter:meta/muse-wonder-standard for a request that meets the basis conditions.

Snapshot v19 adds openrouter:deepseek/deepseek-v4.1-flash-1017-standard-max, checked against the OpenRouter endpoint catalog on 2026-10-19. It prices USD 0.3/M input and 1.2/M output from the deepseek peak time-of-day overrides (tied with other default-routed endpoints), and 0.008/M cached input from relace and inference-net/fp8. The 13 default-routed endpoints span 10 distinct price sets, every quantization and context lengths 262,144–1,048,576; the two opt-in DeepInfra flex/priority endpoints are excluded. Do not use this basis with batch, service_tier, :nitro, :floor or tier-suffixed provider slugs. Cache writes and server tools stay unpriced. The generic openrouter:deepseek/deepseek-v4.1-flash-1017 identity and the bound basis are fallback-blocked, not aliases; quote the basis only for requests that meet its conditions. Re-review it when the canonical revision, endpoints, rates or overrides change.

Modality-specific usage

When text, image, audio, or video tokens have different prices, an inclusive token total cannot identify the amount owed. Differentiated bases use exclusive units: text_input_tokens, text_output_tokens, image_input_tokens, image_output_tokens, audio_input_tokens, audio_output_tokens, video_input_tokens, and video_output_tokens. Cached tokens use cached_text_input_tokens, cached_image_input_tokens, or cached_audio_input_tokens and must be excluded from the corresponding uncached count.

text_output_tokens includes reasoning or thinking tokens. Do not pass those tokens separately as reasoning_tokens on a differentiated modality basis.

Pass each billable token in exactly one unit. Do not pass inclusive input_tokens or output_tokens alongside their modality breakdown. These bases leave generic totals unpriced; missing breakdowns return partial or unavailable quotes. Image counts and audio durations are different units and cannot substitute for token counts. An adapter can recover a breakdown only when the provider reports enough information to prove that its parts are disjoint and complete.

OpenRouter's documented audio fields price tokens. Its image and image_output field documentation conflicts with the token-scaled values in the public catalog, so those fields remain unmapped. A price that needs one of those ambiguous fields is not a complete image quote. Prefer provider-reported cost or an application-configured rate whose unit you verified.

The generic identities that cannot select a tier are fallback-blocked: anthropic:claude-opus-5-5, claude-sonnet-5-5 and claude-haiku-5-5; openai:gpt-6.1-sol, gpt-6-luna and decisions; deepseek:deepseek-v4, deepseek-v4-pro, deepseek-v4-flash and deepseek-v4-flash-vision-exp; openrouter:google/gemini-3.1-flash-lite; and the generics listed in the behavior change below. They resolve to unavailable, and neither the OpenRouter catalog nor the Portkey fallback is consulted for them, so a completed response that reports the provider's generic model ID is not priced at a cheaper tier by accident. Provider-reported cost and configured prices still apply. To cost such a response, pass the basis you enforced as the model:

// The application sent this request to global inference with at most 100,000 prompt tokens.
$cost = AiPricing::cost([
    'provider' => 'anthropic',
    'model' => 'claude-haiku-5-5-global-short',
    'usage' => $response->usage,
    'raw' => $response->raw,     // Lets the adapter read Anthropic's cache TTL split.
    'steps' => $response->steps,
]);

$quote = AiPricing::quote('openai', 'gpt-6.1-sol-standard-long', new Usage([
    'input_tokens' => 300_000,
    'output_tokens' => 4_000,
]));

Behavior change (pricing snapshot v12): these generic and dated identities are newly fallback-blocked and no longer take a Portkey or live OpenRouter catalog price. A response that reports one of them, such as gpt-4o or gpt-4.1, now quotes unavailable. Quote the qualified basis you enforced, or configure a price for the generic identity.

  • Native OpenAI generics: openai:gpt-6-astra, gpt-6-sol, gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna, gpt-5.6-cyber, gpt-5.5, gpt-5.5-pro, gpt-5.4, gpt-5.4-pro, gpt-5.4-mini, gpt-5.2, gpt-5.2-pro, gpt-4.1, gpt-4.1-mini, gpt-4o, gpt-4o-mini, chat-latest, gpt-rosalind-research, gpt-daybreak-blue-latest, gpt-daybreak-red-latest and gpt-5-search-api.
  • Native OpenAI dated IDs: openai:gpt-5.5-2026-04-23, gpt-5.5-pro-2026-04-23, gpt-5.4-2026-03-05, gpt-5.4-pro-2026-03-05, gpt-5.4-mini-2026-03-17, gpt-5.2-2025-12-11, gpt-5.2-pro-2025-12-11, gpt-4.1-2025-04-14, gpt-4.1-mini-2025-04-14, gpt-4o-2024-08-06, gpt-4o-2024-11-20 and gpt-4o-mini-2024-07-18.
  • Native Anthropic generics: anthropic:claude-fable-5-1, claude-mythos-5-1, claude-fable-5, claude-mythos-5, claude-opus-5, claude-opus-4-8, claude-opus-4-7, claude-opus-4-6 and claude-sonnet-4-6.
  • Native Gemini generics: gemini:gemini-3.8-flash, gemini-3.7-flash, gemini-3.6-flash, gemini-3.5-flash, gemini-3.5-flash-lite, gemini-3.1-flash-lite, gemini-3.1-pro-preview, gemini-3.1-pro-preview-customtools, gemini-3-flash-preview, gemini-2.5-pro, gemini-2.5-flash, gemini-2.5-flash-lite, gemini-flash-latest, gemini-flash-lite-latest and gemini-pro-latest.
  • DeepSeek: deepseek:deepseek-flash.
  • Qwen on DashScope: dashscope:qwen3.8-max, qwen3.8-max-0902, qwen3.8-flash, qwen3.7-max, qwen3.7-max-2026-05-20, qwen3.7-max-2026-06-08, qwen3.7-plus, qwen3.7-plus-2026-05-26, qwen3.7-flash, qwen3.7-flash-2026-07-15, qwen3-max, qwen3-max-2026-01-23, qwen3-max-2025-09-23, qwen-plus, qwen-plus-latest, qwen-plus-2025-12-01, qwen-plus-2025-09-11, qwen-plus-2025-07-28, qwen-flash, qwen-flash-2025-07-28, qwen3-coder-plus, qwen3-coder-plus-2025-09-23, qwen3-coder-plus-2025-07-22, qwen3-coder-flash and qwen3-coder-flash-2025-07-28.
  • OpenRouter OpenAI: openrouter:openai/gpt-6.1-sol, gpt-6.1-sol-pro, gpt-6-astra, gpt-6-astra-pro, gpt-6-sol, gpt-6-sol-pro, gpt-6-luna, gpt-6-luna-pro, gpt-5.6-sol, gpt-5.6-sol-pro, gpt-5.6-terra, gpt-5.6-terra-pro, gpt-5.6-luna, gpt-5.6-luna-pro, gpt-5.5, gpt-5.4, gpt-5.4-mini, gpt-4.1, gpt-4.1-mini, gpt-4o-mini, gpt-oss-120b and gpt-oss-20b.
  • OpenRouter Anthropic: openrouter:anthropic/claude-fable-5, claude-opus-5.5, claude-opus-5, claude-opus-4.8, claude-opus-4.7, claude-opus-4.6, claude-opus-4.5, claude-sonnet-5.5, claude-sonnet-5, claude-sonnet-4.6, claude-haiku-4.5 and claude-haiku-5.5.
  • OpenRouter Gemini: openrouter:google/gemini-3.6-flash, gemini-3.5-flash-lite, gemini-3.5-flash, gemini-3.1-pro-preview, gemini-3.1-pro-preview-customtools, gemini-2.5-pro and gemini-2.5-pro-preview.
  • OpenRouter DeepSeek, Qwen, Kimi and GLM: openrouter:deepseek/deepseek-v4.1-flash, deepseek-v4-pro-0813, deepseek-v4-pro, deepseek-v4-flash, deepseek-v4-flash-0731, deepseek-v3.2; qwen/qwen3.7-plus, qwen3.7-max, qwen3.7-flash, qwen3.8-2.4t-a95b, qwen3.8-27b, qwen3-coder-flash, qwen3-coder, qwen-plus; moonshotai/kimi-k3, kimi-k2.7-code, kimi-k2.6; and z-ai/glm-5.3, glm-5.3-flash, glm-5.2, glm-5.1, glm-5, glm-4.7, glm-4.6, glm-4.5-air.

Anthropic bills cache writes by TTL: a 5-minute write and a 1-hour write have different rates. The Anthropic bases therefore price cache_write_input_tokens_5m and cache_write_input_tokens_1h and publish no generic cache_write_input_tokens rate. The adapters map Anthropic's usage.cache_creation.ephemeral_5m_input_tokens and ephemeral_1h_input_tokens to those units and keep the aggregate cache_creation_input_tokens as cache_write_input_tokens. The calculator treats the three units as one family and never bills the split on top of the aggregate:

  • When every reported TTL count has a TTL rate, the split bills at those rates.
  • When the price only has a generic cache_write_input_tokens rate, as remote catalogs do, the reported aggregate bills at that rate, as it did before the split was mapped.
  • An aggregate with no split cannot be priced on an Anthropic basis. It stays a missing unit and the quote is partial, because the package does not guess which TTL was written.

laravel/ai normalizes Anthropic usage to a single cacheWriteInputTokens count. For a non-streamed response, the adapter recovers the split from the response's raw HTTP response, summed across steps for tool loops, and uses it only when it adds up to the reported aggregate. Streamed and serialized responses carry no raw response, so their cache writes keep a partial quote on an Anthropic basis. Callers that record the split themselves can pass cache_write_input_tokens_5m and cache_write_input_tokens_1h directly.

Web searches bill per search on the bases that publish a web_searches rate, which is the provider's native search rate. Anthropic and OpenRouter report the count as usage.server_tool_use.web_search_requests; the normalized, Claude and gateway adapters read it from the usage, and the Laravel AI adapter reads it from the raw response of each step. An Anthropic count maps to web_searches. OpenRouter's count covers every engine it ran (native, Exa, Firecrawl, Parallel or Perplexity, whose fees depend on the engine, mode and result count) without saying which, so it maps to the distinct openrouter_web_searches unit. No snapshot basis prices that unit, so the quote is partial rather than complete at the wrong rate. When your OpenRouter request pinned the native engine on a model that supports native search, declare it on the observation and the count prices as web_searches:

$cost = AiPricing::cost([
    'provider' => 'openrouter',
    'model' => 'anthropic/claude-sonnet-5.5-standard-max',
    'usage' => $response->usage,
    'raw' => $response->raw,
    'steps' => $response->steps,
    'web_search_engine' => 'native', // The request sent engine "native".
]);

A provider-reported usage.cost still wins, and a web_searches or openrouter_web_searches count you pass yourself is used as given. When only some steps of a laravel/ai response have a readable raw response and those report searches, the known count is a lower bound, so it becomes the unpriced web_search_requests_incomplete unit and the quote is partial.

Known limitations:

  • OpenAI usage reports no search count, so the adapters do not count OpenAI web searches yet. On an OpenAI basis with a web_searches rate, pass the number of web_search_call items whose action is search, or those searches go unbilled.
  • Streamed and serialized laravel/ai responses carry no raw response, so their Anthropic cache-write TTL split and web search counts are not recovered.
  • laravel/ai's openai-compatible driver drops cache-write counts (Kimi cache_write_tokens, Qwen cache_creation_input_tokens). Through that driver, cache writes on the moonshot:kimi-k3 and dashscope:* bases bill as uncached input: exact for Kimi 5-minute writes, but short for Kimi 1-hour writes (3.00/M) and Qwen explicit cache creation (25%).
  • OpenRouter web search counts do not say which engine ran, so they stay unpriced (openrouter_web_searches) and keep the quote partial unless the observation declares web_search_engine: 'native'.
  • Gemini cache writes on OpenRouter stay unpriced, both in the live catalog and on the snapshot bases, so a Gemini cache-write count keeps the quote partial.

Snapshot entries include source and retrieval metadata in resources/pricing/provider-skus.php. Future rate changes should follow .agents/skills/fetching-provider-pricing; runtime code never scrapes provider pricing pages.

Default behavior

You can call AiPricing::cost() without configuration.

  • The default currency is USD.
  • Laravel AI text and embedding responses are adapted from their public usage and metadata.
  • OpenRouter text responses can use provider-reported usage.cost when Laravel AI exposes it.
  • Other built-in providers usually expose usage only. The package uses a compatible catalog price when one is available.
  • The package does not store prompts or model output, create database records, or make foreign-exchange conversions.

If you need an exact application rate, a region-specific Bedrock rate, or a known internal rate for a local model, configure the price yourself.

Configuring prices

Publish the configuration file when your application needs its own price list:

php artisan vendor:publish --tag=laravel-ai-pricing-config

Prices use a provider:model key. Use decimal strings for rates and divisors:

// config/ai-pricing.php
'prices' => [
    'openai:gpt-5-mini' => [
        'input_tokens' => [
            'amount' => '0.25',
            'per' => '1000000',
            'currency' => 'USD',
        ],
        'output_tokens' => [
            'amount' => '2.00',
            'per' => '1000000',
            'currency' => 'USD',
        ],
    ],
],

Configured prices are used before remote catalogs. A configured identity replaces the snapshot definition; its units are not merged with built-in units. For example, an xai:grok-4.6 override that still prices search tools must include every search unit it needs to bill — searches, x_search_posts, and x_search_profiles — because configuring only some of them leaves the rest unpriced. Provider-reported cost still takes precedence because it describes the completed request.

Quoting a request before it runs

Use quote() when you know the provider, model, and expected usage before a request is sent:

use Jkudish\LaravelAiPricing\Facades\AiPricing;
use Jkudish\LaravelAiPricing\ValueObjects\Usage;

$quote = AiPricing::quote(
    provider: 'openai',
    model: 'gpt-5-mini',
    usage: Usage::tokens(input: 1_000, output: 250),
);

if ($quote->amount !== null && $quote->amount->isLessThan('0.01')) {
    // Continue with this estimated request.
}

A quote uses the same pricing sources and calculation rules as cost(), but it has no completed response and no provider-reported amount. Use a cost result for accounting after a request finishes. Use a quote to decide whether to send a request.

Prices that change on a known date

Some prices change on an announced date. Gemini 3.8 and 3.6 Flash, for example, cost USD 0.75 per million input tokens and 3.75 per million output tokens through 2026-12-31, and 1.50 and 7.50 from 2027-01-01. A price definition can carry an ordered list of dated rate windows instead of one set of rates. Each window applies from effective_from (inclusive) until effective_until (exclusive), in UTC unless the vendor states a timezone. The windows must be contiguous and must not overlap; only the first may be open at its start and only the last at its end. Every window prices the same units.

  • An actual cost uses the window in effect when the request ran. Pass that time as at when you cost a response later; without it, the package uses the current time.
  • A pre-run estimate bounds a run that can bill until its deadline. Pass the deadline as until, and each rate is the highest rate of every window that overlaps the interval from at (default now) to until. Rates are compared unit by unit, so an estimate can combine the input rate of one window with the output rate of another.
  • A time or interval that no window fully covers quotes unavailable rather than guessing.
  • A price without windows resolves exactly as before. at and until have no effect on it.
use Jkudish\LaravelAiPricing\Facades\AiPricing;
use Jkudish\LaravelAiPricing\ValueObjects\PricingObservation;

// The most this run can cost if it is still billing at its deadline.
$estimate = AiPricing::quote('gemini', 'gemini-3.8-flash-standard', $usage, until: $deadline);

// A completed request, costed later at the rate in effect when it ran.
$cost = AiPricing::cost($response, at: $requestStartedAt);

// The same fields on a resolver observation.
$quote = $resolver->resolve(new PricingObservation($identity, $usage, pricedAt: $startedAt, pricedUntil: $deadline));

A quote's provenance lists the windows that priced it under rate_windows: the one in effect for an actual cost, or every overlapping window for an estimate. In the package snapshot, a windowed entry replaces rates with rate_windows:

'gemini:gemini-3.8-flash-standard' => [
    'source' => 'https://ai.google.dev/gemini-api/docs/pricing',
    'rate_windows' => [
        ['effective_from' => null, 'effective_until' => '2027-01-01T00:00:00+00:00', 'rates' => [
            'input_tokens' => ['amount' => '0.75', 'per' => '1000000'],
            'output_tokens' => ['amount' => '3.75', 'per' => '1000000'],
            // ...
        ]],
        ['effective_from' => '2027-01-01T00:00:00+00:00', 'effective_until' => null, 'rates' => [
            'input_tokens' => ['amount' => '1.50', 'per' => '1000000'],
            'output_tokens' => ['amount' => '7.50', 'per' => '1000000'],
            // ...
        ]],
    ],
],

Construct windowed definitions in code with new PriceDefinition($identity, [], $source, rateWindows: [new RateWindow($from, $until, $rates), ...]). Configured prices do not support windows yet.

Streaming responses

For streamed responses, wait until the stream has been consumed before resolving its cost:

$response = (new ReceiptOcrAgent)->stream($prompt);

$response->then(function ($response): void {
    $cost = AiPricing::cost($response);

    // Persist $cost->toArray() with your application's job or agent-run record.
});

foreach ($response as $event) {
    // Send each stream event to the client.
}

Recording costs

Store the result with the application record that represents the request, job, evaluation, or agent run:

$response = $agent->prompt($prompt);
$cost = AiPricing::cost($response);

$pricing = [
    'provider' => $response->meta->provider,
    'model' => $response->meta->model,
    'pricing' => $cost->toArray(),
];

toArray() includes the cost object, source, completeness, missing units, pricing snapshot, and provenance when available. Saving that data preserves how you arrived at an earlier result, even if a catalog changes later.

Failed or blocked requests can still be billable when a provider does not expose usage. Do not record those requests as zero-cost.

Catalog caching and offline mode

Prewarm the remote catalogs your application uses:

php artisan ai:pricing:sync
// config/ai-pricing.php
'offline' => true,
'cache_store' => null,
'cache_ttl' => 86_400,
'portkey' => [
    'endpoint' => 'https://configs.portkey.ai/pricing/{provider}.json',
    'providers' => ['openai', 'anthropic'],
],

Offline mode makes no network requests. It uses configured prices and cached catalogs from earlier successful lookups.

Precision and rounding

Amounts use brick/math decimals. Round only when you cross a display or billing boundary:

use Brick\Math\RoundingMode;
use Jkudish\LaravelAiPricing\Enums\RoundingBoundary;

$display = $cost->cost?->at(
    RoundingBoundary::Display,
    RoundingMode::HalfUp,
);

Mixed-currency arithmetic throws an exception. Version 0.1 does not perform foreign-exchange conversion.

Compatibility

  • PHP 8.4 and newer.
  • Laravel 13 for the full development and test matrix.
  • Laravel 12 for clean consumer installation, package discovery, and command registration.
  • No runtime dependency on Pest or Laravel AI.

Stability

The package follows Semantic Versioning. The public API may evolve between minor releases before 1.0.0; breaking changes will be documented in the changelog.

Roadmap

See roadmap.md for planned custom catalogs, provider-native sources, pricing freshness diagnostics, and quote inspection tooling.

Contributing

Contributions are welcome. See CONTRIBUTING.md and the Code of Conduct.

Security

Please report vulnerabilities privately according to SECURITY.md.

Sponsoring

If this package helps your work, consider sponsoring its development.

License

Laravel AI Pricing is open-source software licensed under the MIT license.