Tutorial
How to Use gemini-omni-1.2-flash via the HiAPI API: curl and Python
On this page
What a gemini-omni-1.2-flash request looks like
Before you write a single line of code, it helps to understand what a gemini-omni-1.2-flash call actually consists of on HiAPI. Every request you send is a JSON object delivered to a single endpoint, authenticated with your HiAPI API key. The structure is consistent across models, which means once you learn it for this model you can reuse the pattern elsewhere.
At a high level, a request contains four kinds of information:
- The model identifier — the string
gemini-omni-1.2-flash, telling HiAPI which model to route your job to. - The input — the content you want the model to work on. Depending on the modality you are targeting, this is expressed as a prompt or a structured input field.
- Generation parameters — options like duration and resolution that shape the output. These are the knobs you will tune later in this guide.
- Request metadata — anything the platform needs to identify and track your job, such as a client-side reference you can use for correlation.
The response shape
The response is equally predictable. A synchronous call returns the result directly inside a result field. An asynchronous call returns a job handle — an identifier you use to look up the status and, eventually, the output. Knowing which of these two you are dealing with up front saves a lot of debugging later.
Why the shape matters
Most first-integration failures come down to request shape: a missing field, a wrongly typed parameter, or an assumption that a call is synchronous when it is not. If you internalize this anatomy before writing code, the curl and Python examples that follow become straightforward translations rather than magic incantations.
One practical habit: keep the exact JSON body you send in a variable or a file. When something fails, you want to be able to look at precisely what went over the wire, not reconstruct it from memory.
Authentication in one line
Every request carries your API key in an authorization header. Treat the key as a secret, load it from an environment variable rather than hardcoding it, and never commit it to version control. That single discipline prevents the most common security mistake in API integrations.
Your first working request with curl
The fastest way to confirm your key, endpoint, and request shape are all correct is a curl call. It removes every layer of abstraction between you and the API, so if it works, you know the problem (if any) lives in your code, not your setup.
Step 1: Store your key
Put your HiAPI API key in an environment variable so it never appears in your shell history or in a shared script:
export HIAPI_API_KEY="your_key_here"
Step 2: Build the request body
Write the JSON body to a file. This keeps the curl command readable and gives you a reusable artifact:
cat > request.json <<'EOF'
{
"model": "gemini-omni-1.2-flash",
"input": {
"prompt": "Describe what you want the model to generate."
},
"parameters": {
"duration": 5,
"resolution": "720p"
}
}
EOF
The exact parameter values depend on your use case; the structure is what matters here. Keep duration and resolution modest on the first call so you get a fast, cheap signal that the pipeline works.
Step 3: Send it
curl -sS -X POST "https://api.hiapi.ai/v1/generate" \
-H "Authorization: Bearer $HIAPI_API_KEY" \
-H "Content-Type: application/json" \
--data @request.json
Step 4: Read the response
If the request is synchronous, you will see the generated result in the response body. If it is asynchronous, you will receive a job handle instead — a job ID plus a status field. Note that ID; you will need it to poll.
Pipe the output through a JSON formatter if your terminal supports it, or save it to a file so you can inspect it carefully:
curl -sS -X POST "https://api.hiapi.ai/v1/generate" \
-H "Authorization: Bearer $HIAPI_API_KEY" \
-H "Content-Type: application/json" \
--data @request.json > response.json
Step 5: Confirm before you scale
Do not start tuning duration, resolution, or batching until this bare call succeeds and you can read the output. A green first request is your baseline; everything after that is incremental change you can compare against it.
Porting the call to Python
Once curl works, porting to Python is mechanical. The goal is a small, readable client that mirrors the request exactly, so if the Python call fails you can diff it against the curl version field by field.
A minimal client
import json
import os
import requests
API_KEY = os.environ["HIAPI_API_KEY"]
ENDPOINT = "https://api.hiapi.ai/v1/generate"
payload = {
"model": "gemini-omni-1.2-flash",
"input": {
"prompt": "Describe what you want the model to generate."
},
"parameters": {
"duration": 5,
"resolution": "720p"
},
}
headers = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
}
response = requests.post(ENDPOINT, headers=headers, json=payload, timeout=60)
response.raise_for_status()
data = response.json()
print(json.dumps(data, indent=2))
What to notice
json=payloadserializes the dict for you, which is why the body matches the curl file rather than being a hand-built string.raise_for_status()turns non-2xx responses into exceptions, so failures surface immediately instead of silently returning an error body you then try to parse as a result.timeout=60prevents your script from hanging indefinitely on a stalled connection. Pick a value based on how long you expect generation to take.
Handling both response shapes
Because a call may return either a result or a job handle, branch on the response rather than assuming one shape:
if "job_id" in data:
print("Async job started:", data["job_id"])
else:
print("Result ready")
This small check is the difference between a client that works in both modes and one that crashes the first time the platform decides your job needs to run asynchronously.
Keep it in one function
Wrap the call in a function that takes the prompt, duration, and resolution as arguments. That makes it trivial to run the same code with different parameters when you start tuning, and it keeps the request shape defined in exactly one place.
Async jobs and polling for results
Some gemini-omni-1.2-flash requests complete quickly enough to return a result inline. Others take longer, and HiAPI responds with a job handle instead. Your integration must handle both, and the async path is where most fragile clients break.
Recognizing an async response
An async response includes a job identifier and a status. Instead of a finished output, you get a promise: the work has been accepted and will be processed. Your job is to check back.
Polling correctly
The naive approach — hammering a status endpoint in a tight while True loop — is bad for two reasons: it wastes your rate limit budget, and it puts unnecessary load on the platform without getting you a result any faster.
A better pattern uses interval backoff with a cap:
import time
def poll_job(job_id, base_delay=1.0, max_delay=10.0, max_wait=300.0):
elapsed = 0.0
delay = base_delay
while elapsed < max_wait:
status = get_job_status(job_id)
if status["state"] == "succeeded":
return status
if status["state"] == "failed":
raise RuntimeError(status.get("error", "job failed"))
time.sleep(delay)
elapsed += delay
delay = min(delay * 2, max_delay)
raise TimeoutError(f"job {job_id} did not finish in time")
The three rules of polling
- Start small, grow slowly. A short first interval catches fast jobs cheaply; doubling up to a cap keeps slow jobs from being checked too often.
- Always set a maximum wait. Without it, a stuck job hangs your process forever. A timeout that raises is far better than a silent hang.
- Distinguish success, failure, and pending. Only two of those should stop the loop, and only one should return a result.
Prefer webhooks when available
If your workload is heavy, polling every job does not scale well. Where HiAPI offers completion callbacks, use them to receive results instead of repeatedly asking. For interactive tools and low-volume scripts, polling with backoff is perfectly adequate.
Either way, treat the job handle as the durable identifier of the work. Store it, log it, and use it to reconcile results later.
Choosing duration and resolution
Duration and resolution are the two parameters that most directly shape your output — and your bill and wait time. Neither has a single correct value; the right choice depends on what you are building. What matters is that you choose them deliberately rather than copying numbers from an example.
Duration
Duration controls how long the generated output runs. Longer durations give you more content but take more compute to produce, which affects both latency and how the request is billed (billing is based on output duration). Some practical guidance:
- Start short when testing. A brief duration proves the pipeline end to end without wasting time on every iteration.
- Match duration to purpose. A short clip for a preview or thumbnail does not need the length of a full deliverable.
- Do not pad speculatively. Generate the length you will actually use; trimming afterward gains you nothing.
Resolution
Resolution controls output fidelity. Higher resolution means more detail and larger payloads, with corresponding increases in processing time and cost. The tradeoffs to weigh:
- Preview and draft work does not need high resolution — it is a correctness check, not a final product.
- Final deliverables may justify the higher setting, especially if the output is shown at full size.
- Bandwidth and storage matter too: high-resolution outputs are heavier to transfer and retain.
Tune one variable at a time
When you adjust parameters, change one at a time and compare against your baseline curl call. Changing duration and resolution together makes it impossible to attribute a change in quality, latency, or cost to either one. Keep a small matrix of settings you have tested and their observed behavior.
Reason about cost as a formula, not a number
Because pricing lives in the site's pricing panel, treat cost as a function: total cost scales with output duration and, for higher resolutions, with the resulting output size and processing. Your job is to know which parameters drive that function, then check current pricing before committing to production volumes. That way your estimate stays correct even when prices change.
Common errors and how to fix them
Most first-integration failures fall into a handful of buckets. Work through them in this order — each step depends on the previous ones being correct, so checking out of order sends you chasing symptoms.
1. Request shape
Symptom: a validation error or a message about a missing or unexpected field.
Fixes: confirm the body is valid JSON (a trailing comma is the classic culprit), confirm the model field is exactly gemini-omni-1.2-flash, and compare your payload against the working curl example line by line. If curl works and Python does not, diff the two request bodies.
2. Parameters
Symptom: an error naming duration or resolution, or an unexpected output size.
Fixes: check types (a number where a number is expected, a string where a string is expected) and check that values are within accepted ranges. If a parameter is silently ignored, verify it is nested where the API expects it rather than at the top level.
3. Authentication
Symptom: 401 or 403 responses.
Fixes: confirm the key is present in the Authorization header with the Bearer prefix, that the environment variable actually contains a value (an empty string looks a lot like a wrong key), and that you have not copied surrounding whitespace or quotes into the key. Regenerate the key if you suspect it leaked.
4. Job status
Symptom: you poll and never see success, or you treat a pending job as a failure.
Fixes: confirm you are polling the correct job ID, that your loop recognizes all statuses (pending, running, succeeded, failed), and that your maximum wait is long enough for realistic jobs. Log each status transition so you can see where it stalls.
5. Rate limits and transient failures
Symptom: 429 responses or intermittent 5xx errors.
Fixes: back off and retry with jitter rather than retrying immediately. If you are polling many jobs, reduce concurrency. Transient errors are normal; a client that retries intelligently rides them out.
A debugging discipline
When something breaks, change one thing at a time and re-run the smallest possible request. Keep the raw response body — error messages usually name the exact field or condition, and reading them carefully saves more time than any amount of guessing.
A production integration checklist
A script that works once on your laptop is not an integration. Before you ship, close these gaps.
Retries with backoff
Wrap network calls in a retry policy that handles transient failures — timeouts, connection resets, 429s, and 5xx responses. Use exponential backoff with jitter, cap the number of attempts, and never retry a request that failed validation; retrying a malformed body just fails again more slowly.
Timeouts everywhere
Set an explicit timeout on every HTTP call. Distinguish between the connect timeout and the read timeout, and make sure your timeout for a generation request is at least as long as a realistic generation takes — but bounded.
Idempotency around jobs
Network blips happen after the server has accepted your request but before you see the response. If you retry blindly, you may create duplicate jobs. Attach a client-generated reference to each logical request so you can detect and reuse an existing job instead of creating a new one, and store job handles in durable storage keyed by that reference.
Logging that answers questions
Log the model name, parameter values (duration, resolution), the job handle, status transitions, and latency for each request. Never log your API key or full prompt content if it may contain sensitive data. When something goes wrong at 3 a.m., these logs are what let you reconstruct exactly what happened.
Observability and alerting
Track success rate, error breakdown by type, and end-to-end latency for both the request and the job lifecycle. Alert on sustained error rates rather than single failures. A dashboard that separates validation errors from transient ones tells you instantly whether you have a bug or a bad day on the network.
Configuration hygiene
Keep the endpoint, model name, and default parameters in configuration rather than scattered through your code. Load the API key from a secrets manager or environment variable. If pricing and limits are relevant to your planning, consult the pricing panel rather than hardcoding figures, since those change.
Work through this list once and your gemini-omni-1.2-flash integration will handle real traffic instead of just your first test. Start from the working curl call, port it to Python, and build outward from there.
Related articles
View all articles →-
Tutorial
How to Call kimi-k3.1-pro via the HiAPI API: curl, Python, and a Working Request
A hands-on integration guide covering endpoints, request parameters, streaming, tool calls, and error triage
18 min read -
Tutorial
ElevenLabs Music API on HiAPI: Generate Music with curl, Python, and Prompt Recipes
A hands-on tutorial for calling elevenlabs/music-v2.5 through HiAPI, plus copy-paste prompt recipes for style, mood, and duration
12 min read -
Tutorial
How to Use gpt-image-2.5-sunburst/image-to-image via the HiAPI API: curl and Python
A working request, reference-image upload flow, and error triage for developers
10 min read