Call generateContent from Your Terminal with Fluxo
Native generateContent calls without leaving your terminal
When I am testing an API integration, I want one request I can run, inspect, and repeat before touching application code. This walkthrough uses the native generateContent request shape through Fluxo, first with curl and then with Python’s standard library. We will send a contents array, save the response, and extract the returned text.
Fluxo provides one key and one base URL, https://api.fluxorelay.com, across Claude, GPT, Gemini, DeepSeek, Kimi, GLM, Qwen, Grok, and more. Here we will use Gemini 3.8 Flash as the concrete example. Native generateContent requests retain their own payload structure; they are not Chat Completions requests with a different URL.
Set your Fluxo key and exact model identifier
If you want to follow along, you can create a Fluxo account and obtain an API key. Copy the API model identifier for Gemini 3.8 Flash from the model listing rather than converting its display name into a guessed slug. The identifier becomes part of the request path.
Run these commands in Bash. The key prompt hides your input, and neither secret needs to appear directly in your shell history.
export FLUXO_BASE_URL='https://api.fluxorelay.com' — read -r -s -p 'Fluxo API key: ' FLUXO_API_KEY; printf '\n'; export FLUXO_API_KEY
read -r -p 'Exact Gemini 3.8 Flash API model identifier: ' FLUXO_MODEL; export FLUXO_MODEL
Keep the model value to the identifier itself, without a leading models/ prefix. The commands below supply that prefix. Do not commit your key, paste it into issue reports, or enable shell tracing while testing authenticated requests.
Send a native generateContent request with curl
The native route is /v1beta/models/{model}:generateContent. Its request uses contents, with text nested inside parts. Run this single-line command to save the response body and print the HTTP status separately:
curl --silent --show-error --fail-with-body --output response.json --write-out 'HTTP %{http_code}\n' "${FLUXO_BASE_URL}/v1beta/models/${FLUXO_MODEL}:generateContent" --header "Authorization: Bearer ${FLUXO_API_KEY}" --header 'Content-Type: application/json' --data '{"contents":[{"role":"user","parts":[{"text":"Explain an HTTP timeout in two short sentences."}]}],"generationConfig":{"temperature":0.2,"maxOutputTokens":512}}'
This uses a non-streaming response so that debugging stays straightforward. The --fail-with-body option requires curl 7.76.0 or newer and preserves an error body while returning a failing exit status for HTTP errors. Inspect the saved JSON before wiring the request into anything larger:
python3 -m json.tool response.json — Successful text responses normally place output under candidates, then content, then parts. This command prints text parts from the first candidate and safely handles an absent candidate:
python3 -c 'import json; r=json.load(open("response.json")); c=r.get("candidates", []); print("\n".join(p["text"] for p in (c[0].get("content", {}).get("parts", []) if c else []) if "text" in p))'
Repeat the generateContent request with Python
You do not need an SDK to reproduce that request. This single-line Python command reads the same environment variables, serializes the same native payload, applies a sixty-second timeout, and prints the complete response JSON:
python3 -c 'import json, os, urllib.request; base=os.environ["FLUXO_BASE_URL"].rstrip("/"); model=os.environ["FLUXO_MODEL"]; payload={"contents":[{"role":"user","parts":[{"text":"Explain an HTTP timeout in two short sentences."}]}],"generationConfig":{"temperature":0.2,"maxOutputTokens":512}}; req=urllib.request.Request(f"{base}/v1beta/models/{model}:generateContent", data=json.dumps(payload).encode("utf-8"), headers={"Authorization":"Bearer "+os.environ["FLUXO_API_KEY"],"Content-Type":"application/json"}, method="POST"); response=urllib.request.urlopen(req, timeout=60); print(json.dumps(json.load(response), indent=2))'
In application code, catch urllib.error.HTTPError and read its response body for diagnosis. Handle transport errors separately: an HTTP rejection and a connection timeout need different fixes.
Check native payloads before adding retries
- Check authentication failures against the key loaded into your current shell.
- Check routing failures against the exact model identifier and native endpoint path.
- Inspect empty candidates and finish reasons before assuming text extraction failed.
- Avoid blind retries because repeated generations can create additional billable usage.
Fluxo bills per real token, including cache reads and writes, with no monthly fee. It also works with Claude Code, Codex, Gemini CLI, and any OpenAI SDK, but those integrations do not change this native payload. Users earn a referral share when people they invite pay. If you need help with a failing request, leave a note on the contact page after signing in, including a sanitized error body rather than your key.