Guides
How to Estimate AI Music API Cost Before Generation
- Written by
- Sonilo Team
- Published

Estimate an AI music API job before submission with one conservative formula: billable seconds per variant multiplied by variants, jobs, the published per-second rate, and the account discount factor. Keep a second paid-ceiling figure that ignores trial calls, then block the POST when the estimate exceeds the job or campaign budget.
Estimate an AI music API job before submission with one conservative formula: billable seconds per variant multiplied by variants, jobs, the published per-second rate, and the account discount factor. Keep a second paid-ceiling figure that ignores trial calls, then block the POST when the estimate exceeds the job or campaign budget.
By Sonilo Team · Facts verified August 20, 2026
Disclosure: Sonilo publishes this guide and operates the API used as the concrete example. The `ai-music-cost-estimator-v1` module was tested with deterministic inputs and synthetic account responses. It did not submit generation work, inspect a customer invoice, or measure production billing.
Use one pre-submit formula
For one music endpoint, calculate the paid ceiling as:
`max(requested seconds, billing floor) × variants × jobs × rate × discount factor`
The current Sonilo API reference says music generations have a ten-second minimum billable duration. A five-second Text-to-Music request is therefore estimated with ten billable seconds, not five. For requests longer than the floor, use the requested or known source duration.
The current Sonilo API pricing page lists these public standard rates, verified August 20, 2026:
| Music service | Published standard rate | Billing floor | Estimator scope |
|---|---|---|---|
| Video-to-Music | $0.009 per second | 10 seconds | Source duration, 1–360 seconds |
| Text-to-Music | $0.00225 per second | 10 seconds | Requested duration, 5–360 seconds |
Rates are time-sensitive. The calculator pins them to a visible verification date and reads the account-specific discount separately. Recheck the pricing page when the date changes; do not let an old constant become an invisible contract.
Multiply the floor before variants and jobs
Apply the billing floor to one variant first. Then multiply the resulting billable seconds by the number of variants and planned jobs.
The current Video-to-Music reference, Text-to-Music reference, and OpenAPI contract document `variants_num` from 1 to 10. Each variant is a distinct generation, and cost scales linearly. Values above one require async mode and are not covered by free-trial calls.
That ordering matters. Three variants of a four-second Video-to-Music job are not billed as twelve seconds. Each variant first reaches the ten-second floor, so the planning estimate uses thirty billable seconds.
| Planned work | Calculation before discount | Published-rate estimate |
|---|---|---|
| One 4-second video, one variant | 10 × 1 × $0.009 | $0.09 |
| Twenty 60-second text jobs, three variants each | 60 × 3 × 20 × $0.00225 | $8.10 |
| Twenty 90-second video jobs, three variants each | 90 × 3 × 20 × $0.009 | $48.60 |
| Same video batch with a 0.8 account factor | $48.60 × 0.8 | $38.88 |
These are transparent calculations, not quotes or invoices. They assume every planned paid call is accepted at the documented input shape and uses the dated public rate.
Read account terms without generating media
Call `GET /v1/account/services` before the generation request. The current List Services documentation says the authenticated response includes enabled services, requests-per-minute and concurrency limits, `discount_factor`, upload size, and a per-service trial object when the self-serve account has one.
This read answers three pre-submit questions:
- Is the selected music service enabled for this account?
- Does the account have a discount factor different from the public standard rate?
- Are any single-variant trial calls still available?
Keep the API key on the server. The Sonilo API introduction requires Bearer authentication and says keys should not be committed or shipped to client code. The estimator reads `SONILO_API_KEY` from `process.env`, sends it only to `https://api.sonilo.com/v1/account/services`, and does not return it in the result.
The account-services call is not a pricing endpoint. It returns the discount factor but not the public rate table. That is why the example has a dated rate constant rather than pretending all inputs came from one response.
Keep both a trial estimate and a paid ceiling
Trial calls are useful for a first test, but they are a poor campaign budget. A planning tool should return two values:
- Estimated cost:* subtract eligible single-variant trial calls that remain now.
- Paid ceiling:* assume every planned call is paid at the current rate and account factor.
The ceiling remains useful when a trial is consumed by another worker before this batch starts. It also prevents a dashboard from presenting a temporary free allowance as the steady-state unit cost.
If `variants_num` is above one, set trial-covered jobs to zero. The current machine-readable contract explicitly says multi-variant requests are always billed even when trial calls remain.
Do not subtract a trial when the response omits the service's trial entry. Absence is not proof of a free call.
Build the estimator with integer money units
`ai-music-cost-estimator-v1` stores each public rate in micro-dollars instead of multiplying binary floating-point values. It rounds once, after applying the account factor, and renders the result separately.
The core calculation is small:
- `const product = MUSIC_SERVICES[serviceKey];`
- `const billedPerVariant = Math.max(`
- ` durationSeconds,`
- ` product.billingFloorSeconds,`
- `);`
- ``
- `const trialCoveredJobs = variants === 1`
- ` ? Math.min(jobs, trialRemaining)`
- ` : 0;`
- ``
- `const paidJobs = jobs - trialCoveredJobs;`
- `const paidVariantRuns = paidJobs * variants;`
- `const paidCeilingRuns = jobs * variants;`
- ``
- `const billedSeconds = billedPerVariant * paidVariantRuns;`
- `const ceilingSeconds = billedPerVariant * paidCeilingRuns;`
- ``
- `const estimateMicros = discountedMicros({`
- ` rateMicros: product.publishedRateMicrosPerSecond,`
- ` billedSeconds,`
- ` discountScaled,`
- `});`
- ``
- `const paidCeilingMicros = discountedMicros({`
- ` rateMicros: product.publishedRateMicrosPerSecond,`
- ` billedSeconds: ceilingSeconds,`
- ` discountScaled,`
- `});`
The complete module validates service names, endpoint duration limits, variants, jobs, trial counts, the account's enabled-service list, and a discount from greater than zero through one. It accepts both hyphen and underscore service spellings because the current human documentation and example JSON use both forms.
Add a hard budget decision
An estimate is only advisory until it controls the request path. Compare the integer estimate with an explicit maximum before creating `FormData` or opening a generation connection.
- `const estimate = estimateMusicCost(input);`
- ``
- `assertWithinBudget(`
- ` estimate,`
- ` campaign.maximumGenerationUsd,`
- `);`
- ``
- `return submitGeneration(input);`
Keep the budget and estimate in the same durable request record. Useful fields include `pricing_verified_at`, `service`, `requested_seconds`, `billing_floor_seconds`, `variants`, `jobs`, `discount_factor`, `trial_covered_jobs`, `estimated_cost_usd`, `paid_ceiling_usd`, and `budget_usd`.
Do not log the API key, prompt, source URL, temporary output URL, or uploaded filename. The separate safe API logging guide defines a smaller allowlist for operational events.
If the estimate is too high, reject the batch or require an approved change to duration, variant count, job count, or budget. Do not silently reduce creative scope and submit a different request than the user approved.
Place the gate before queue admission and submission
Cost estimation belongs after input facts are known but before billable work can begin:
- Validate the source and determine its duration with the video preflight workflow.
- Read current account services, discount factor, and trial allowance on the server.
- Calculate the trial-adjusted estimate and all-paid ceiling.
- Compare the estimate with the job and campaign budgets.
- Check RPM and concurrent-generation capacity through the generation admission queue.
- Claim the exact request identity through the duplicate-job prevention contract.
- Submit only after all gates pass.
Capacity and cost are different controls. An account can have available concurrency while the campaign lacks budget. It can also have budget while an open generation circuit breaker correctly blocks a new dependency call.
Keep each decision explicit. One failed gate should not mutate the state owned by another.
Treat ambiguous replays as new financial risk
A pre-submit estimate proves what the application intended to spend, not whether a timed-out POST was accepted. If a generation connection ends without a usable response, do not run the calculator again and interpret the same estimate as permission to replay.
Use the durable request record to freeze an ambiguous submission until the application's replay policy permits another POST. The cost ceiling for a deliberate retry should include the possibility that the first attempt was accepted unless the provider contract supplies a recoverable answer.
When an async submission returns a usable task ID, switch to the bounded polling workflow. A status GET is not another generation POST. During deployment, preserve that task ID through the graceful worker handoff instead of submitting the planned job again.
Reconcile estimates with usage after the run
The current Get Usage reference documents `GET /v1/account/usage?days=30` for an authenticated summary and daily breakdown. Use that endpoint for retrospective account usage, then compare aggregate actual cost with the stored estimates.
Track at least:
- Estimated cost before submission.
- Paid ceiling before submission.
- Accepted generation count.
- Observed usage cost for the same accounting window.
- Difference and an explainable reason.
Do not claim a per-job invoice match when the usage response is aggregated by day. Use stable job and task records for internal attribution, and treat the provider's account usage or billing record as the post-run authority.
After success, the budget record does not replace media verification. Copy and validate temporary output through the durable music-file workflow.
The thirteen-test contract
The estimator ran with the official Node.js v22 test runner and no external packages. Thirteen deterministic tests passed on Node.js v22.23.2 on August 20, 2026:
- Normalize hyphen and underscore service names.
- Apply the ten-second floor to short Video-to-Music input.
- Apply the floor to a valid five-second Text-to-Music request.
- Multiply cost by variants and jobs.
- Apply the authenticated account discount factor.
- Separate trial-covered calls from the all-paid ceiling.
- Exclude multi-variant work from trial coverage.
- Reject a service unavailable to the account.
- Reject invalid duration and variant values.
- Parse discounts without floating-point arithmetic.
- Fetch account metadata server-side without returning the key.
- Classify failed account authentication.
- Reject a campaign above its maximum spend.
The tests prove the local formula, validation, response parsing, and budget decision. They do not prove live account eligibility, a final provider charge, an invoice's rounding policy, successful generation, output quality, or campaign economics.
When this calculator is not enough
Do not use this two-service module for Sound Effects, combined music-and-effects, Audio Ducking, Dubbing, or custom services. Each needs its own current rate, billing unit, floor, input limits, and multiplier rules.
Do not use the public standard rate as a substitute for signed custom terms. Read the authenticated discount and reconcile against the account's current commercial agreement.
Do not use a pre-submit estimate as an account balance. The current account-services response documents limits and a discount factor, not a spendable-balance field.
Do not treat trial eligibility as guaranteed availability. Another legitimate request can consume it first.
Do not promise that a budget gate prevents all overspend. Concurrent workers, stale account data, ambiguous accepted requests, retries, and separate services still need durable controls and retrospective reconciliation.
Make cost a gate, not a surprise
Calculate the floor per variant, multiply by variants and jobs, apply the current account factor, and retain both a trial-adjusted estimate and an all-paid ceiling. Store the decision before submission and reject work above budget.
Start with the broader Video-to-Music API guide, keep the key behind the server-side Sonilo boundary, and verify current rates, floors, variants, and account fields in the Sonilo API reference before deploying the estimator.


