Guide
Controlling AI Image and Video API Costs on HiAPI: Tiers, Batching, and Retry Avoidance
Why image and video generation spend drifts
Generation workloads rarely blow up in a single dramatic spike. More often, spend drifts upward in small, unremarkable steps: one retry here, one duplicate request there, a flagship model used for a draft that never ships. Each step looks harmless in isolation, which is exactly why the total is hard to attribute later.
The drift usually comes from three places. First, retries and duplicates: a client timeout triggers a resend while the original request is still processing, so you pay twice for one visible result. Second, tier misuse: exploratory prompts or bulk variant generation quietly run on your most capable model because it was the default. Third, unbounded fan-out: a feature that generates one asset per user action slowly becomes five or ten as product requirements grow, without anyone revisiting the cost model.
Because these are behavioral patterns rather than incidents, they do not announce themselves in error logs. The only reliable way to catch drift is to make spend visible per feature and per tier from the first day of integration, so a regression shows up as a line on a dashboard rather than a surprise at the end of the month. The rest of this guide works through the levers you actually control: tier selection, request shape, batching, retries, and instrumentation.

Fast versus flagship tiers: matching tier to job
The single highest-leverage decision is which tier a given generation task belongs in. HiAPI exposes fast and flagship tiers for image and video generation, and the right default depends on what the output is for, not on what the prompt is about.
A practical split looks like this:
Jobs that belong on the fast tier
- Drafts and previews. Anything a user will look at once to make a decision, then discard.
- Bulk variants. When you generate many candidates and surface only a few, the marginal value of each individual output is low.
- Internal exploration. Prompt iteration during development, regression fixtures, and pipeline smoke tests.
- Placeholder and progressive rendering. A quick low-fidelity asset shown while a final version is requested or confirmed.
Jobs that belong on the flagship tier
- Final deliverables. Assets that ship to the end user, enter a publication workflow, or are billed to a customer.
- Quality-critical content. Cases where a visibly weak output triggers a support ticket or a regeneration, which costs more than the upgrade would have.
- Small, high-value batches. Where output count is low but each result matters.
Making the split stick
The failure mode is not choosing wrong once; it is letting the flagship model become the path of least resistance. Encode the split in code so it is not a per-call judgment. Give each feature an explicit tier constant, default new features to the fast tier, and require a deliberate change to promote a feature to flagship. When a fast-tier draft is approved for final use, that is the moment to issue a single flagship request for the shipping asset rather than regenerating everything on the expensive tier.
One caveat: tier choice and output count interact. Sending a large variant sweep to the flagship tier multiplies cost by the batch size, so review those two settings together rather than independently.

Reading per-character and per-second pricing
Generation requests on HiAPI are not billed as a single opaque unit. Text-driven image requests and video requests have different cost drivers, and understanding the shape of a request is what lets you estimate it before you send it.
Text input is priced by character
For image generation driven by a prompt, the input side scales with the length of the text you send. That has two consequences worth designing around:
- Long, repetitive prompts cost more per request than tight ones, and the extra words usually do not improve the output. Review prompt templates for boilerplate that can be trimmed once in a shared constant.
- Any feature that composes prompts from user input, retrieved context, or style libraries needs a length ceiling. Cap input length at the application layer so a pathological input cannot silently inflate every request in a loop.
Video output is priced by second
For video generation, the dominant driver is output duration. This makes duration the primary budget dial: a feature that generates a short clip per action has a fundamentally different cost profile than one that renders a longer sequence. Decide duration per feature deliberately, and treat it as a product parameter rather than an implementation detail.
Estimating before sending
A useful habit is to compute a per-request estimate from these two inputs before dispatch: character count of the composed prompt, and intended output seconds. You do not need a precise figure to benefit. What you need is a consistent estimate that lets you rank requests, set per-feature ceilings, and notice when a template change makes prompts suddenly much longer or clips suddenly much longer. Do not hardcode any rate into your code; fetch current pricing from the site's pricing panel or a configuration value you can update, and keep your estimator in terms of those inputs.
The broader point is to treat text input and video duration as separate budgets. They move for different reasons and are owned by different parts of a pipeline, so a single combined ceiling hides which one is drifting.

Batching and debouncing generation requests
Before you touch tiers or duration, look at how many requests you are sending. Duplicate and redundant calls are the cheapest cost problem to fix, because the fix is entirely in your application.
Batch where the interface allows it
If a user action produces several related assets, prefer one batched call over a loop of individual calls. Batching reduces overhead per item and gives you one place to apply a cap. When you do batch, sort the work so the highest-value items are early in the batch; if you need to stop early on a budget ceiling, you have already produced the outputs that matter.
Debounce and collapse at the edge
Interactive surfaces generate requests faster than users make decisions. Sliders, prompt editing, and style pickers can fire a generation request on every keystroke or drag event. Debounce those inputs so a request is issued only after the user pauses, and collapse superseded requests: if a user changes the prompt three times in two seconds, only the last state should be generated.
A simple pattern is a request key derived from the normalized inputs. Keep a map of in-flight keys; when a new request arrives with the same key, attach it to the existing call instead of issuing another.
Fan-out limits
Any feature that generates N variants from one action should have an explicit N, chosen per feature and enforced in code rather than in a UI slider the user can push arbitrarily high. Cap concurrency as well: a queue that drains at a bounded rate is easier to reason about than a burst that empties a budget in seconds.
Idempotent results by cache
If the same prompt and settings produce the same asset, cache the result keyed by those inputs and serve repeats from storage. This is the highest-value batching technique for products with heavy repeat usage, and it composes with debouncing: debounce reduces calls within a session, caching eliminates them across sessions.
Designing retries that do not double your bill
Retries exist because networks and distributed systems fail. The problem is that a naive retry is a new paid request, so an unclassified retry policy converts transient failures into a silent cost multiplier. Design retries as a deliberate mechanism, not a loop.
Use idempotency keys
Attach an idempotency key to every generation request, derived from the request's meaningful inputs plus a client-generated request ID. On retry, reuse the same key. The platform can then recognize the retry as the same logical operation rather than a new one. Without a key, a timeout on your side while the request is still processing on the server is indistinguishable from a new request, and you pay for both.
Classify failures before retrying
Not all errors deserve a retry:
- Transient transport errors and timeouts. Retry, with the idempotency key and bounded backoff.
- Rate limiting. Retry after the indicated wait rather than immediately, and reduce concurrency.
- Invalid input errors. Do not retry; the same request will fail again and you have paid for the attempt. Fix the input at the application layer.
- Content policy rejections. Do not retry with the same input. Fail fast and surface the reason.
A failure classifier in front of your retry loop is usually a few dozen lines and prevents the most expensive category of mistake: retrying a deterministic failure.
Cap retries per logical operation
Set a small maximum retry count per logical operation and a per-request time budget. Once exhausted, fail the operation and record it. Unbounded retries on a flaky dependency can turn one user action into many paid attempts, and the user still does not get their asset.
Do not retry inside the user's request path
For long-running video generation, run the retry logic in a background worker with the idempotency key persisted before dispatch. If the client disconnects, the operation still completes and the result is stored, rather than being abandoned and re-requested on the next page load.
Instrumenting spend per feature and tier
You cannot control what you do not measure, and aggregate spend is not enough to control anything. Instrument at the granularity you make decisions at: per feature and per tier.
Log a record per logical operation
For every generation operation, emit one structured log line containing the feature name, the tier used, the request shape (input character count and intended output seconds), whether it was a retry, whether it was served from cache, and the cost your estimator assigns to it. Keep the cost estimate in terms of the pricing inputs rather than a hardcoded rate, so a pricing panel change does not invalidate your history.
Aggregate into a small set of views
Three views cover most needs:
- Cost per feature, so a new feature that is disproportionate to its value is visible immediately.
- Cost per tier, so a silent migration from fast to flagship shows up as a share shift.
- Retry and cache-hit ratios, so duplicate generation and failure loops are visible before they dominate the bill.
Alert on ratios, not just totals
Total spend alerts fire too late. Watch ratios instead: the share of requests that are retries, the share served from cache, and the flagship share of requests within a feature. A sudden rise in the retry ratio usually indicates a failing dependency or a misbehaving classifier, and a rise in flagship share usually indicates a default that drifted.
Tie it to the pipeline
Emit the same feature and tier labels in your request logs and in your application metrics, so an alert links back to the code path. When a cost regression appears, you want to name the feature, the tier, and the request shape that changed, not just observe that the total went up.
A cost-control checklist before you ship
Run through this list before a generation feature reaches production users. Each item is a small amount of work that prevents a category of drift.
- Tier is explicit per feature. Every generation call site names a tier constant, new features default to fast, and promoting a feature to flagship is a reviewed change.
- Draft and final are separate paths. Exploratory and bulk work never inherits the flagship tier by default, and final assets are generated once, deliberately.
- Prompt length is bounded. Templates are reviewed for boilerplate, and user-derived input has an application-layer length ceiling.
- Duration is chosen per feature. Video output length is a product parameter with an explicit default, not an implementation detail.
- Fan-out and concurrency are capped. Variant counts and in-flight requests have explicit limits enforced in code.
- Inputs are debounced and collapsed. Superseded requests are dropped before dispatch, and repeated inputs are served from a cache keyed on normalized inputs.
- Retries are classified, keyed, and capped. Every request carries an idempotency key, deterministic failures are not retried, and each logical operation has a retry ceiling.
- Long-running work is asynchronous. Video generation runs in a worker with the key persisted first, so a client disconnect does not cause a duplicate request.
- Spend is instrumented per feature and tier. Retry ratio, cache-hit ratio, and flagship share have alerts.
- Rates live in configuration. Your estimator reads pricing inputs from a place you can update, so nothing is hardcoded.
Ship the checklist with the feature, not after the first bill. Predictable generation spend comes from a handful of repeated habits, and the small amount of structure above is what keeps tiers, batching, and retries from quietly compounding.
Related articles
View all articles →-
Guide
Getting Started with seedream-5.0-pro/image-to-image: Capabilities, Pricing, and Integration Essentials
Capability boundaries, billing model, and engineering integration practices for ByteDance's image editing model
-
Guide
seedream-5.0-pro Text-to-Image Getting Started Guide: Capability Boundaries, API Integration, and Cost Control
A hands-on developer perspective: from key parameters to a cost estimate of $0.05 per image
-
Guide
Hailuo 2.3 Fast Image-to-Video Getting Started Guide: Capability Boundaries, Pricing, and Integration Practices
MiniMax image-to-video model selection and integration key points for developers