Gemini API quickstart: first call with curl and the Google GenAI SDK
This Gemini API quickstart gets a first working call done in minutes: one curl against the native generateContent route, then the same call from the official Google GenAI SDK in Python or JavaScript. Only the base URL and the key header change — supported requests keep Google's own request shapes, streaming and usage metadata.
·
One endpoint, the native Gemini protocol
To make your first Gemini API call through apiToken.sale, keep the Google protocol exactly as documented and change only two values: the base URL becomes https://router.apitoken.sale and the key is your apiToken.sale key, sent as the x-goog-api-key header. Every request and response keeps the native generateContent shape, so Google's documentation and SDK samples apply to the models and fields this endpoint supports. A few Google features are not available here: cachedContent and external file URIs are rejected (send files as inlineData), and the model list is limited to the published catalogue — the error table below lists each case.
One key and one prepaid balance cover every supported provider — Gemini alongside Claude and GPT. Gemini usage is metered at official Google token rates, and a flat 50% discount is applied before the cost is drawn from your balance. No Google Cloud project or billing account is involved on your side.
For Antigravity CLI, use the one-command setup: curl -fsSL https://apitoken.sale/setup/connect.sh | bash. On Windows PowerShell use irm https://apitoken.sale/setup/connect.ps1 | iex. It installs the native agy command and imports every Gemini model enabled for your key. No Google sign-in is needed.
See also: How to buy a Gemini API key
Create the key and list your catalog
- 01Create a free apiToken.sale account and open the dashboard — no approval step or waitlist.
- 02Generate one API key. It looks like sk-pool-… and works for Gemini, Claude and GPT alike.
- 03Top up any whole-dollar amount by card or crypto; the prepaid balance does not expire.
- 04Export the key as APITOKEN_API_KEY, then list the models your key can actually call:
curl https://router.apitoken.sale/v1beta/models \ -H "x-goog-api-key: $APITOKEN_API_KEY"
Pick an explicit model ID from that response. gemini-3.6-flash is the right default for a first text call; a client library's built-in default may not be in the gateway catalog, and the router only serves the IDs it lists.
First call: generateContent with curl
curl https://router.apitoken.sale/v1beta/models/gemini-3.6-flash:generateContent \
-H "x-goog-api-key: $APITOKEN_API_KEY" \
-H "Content-Type: application/json" \
-d '{"contents":[{"parts":[{"text":"Reply with exactly: connected"}]}]}'The response is the standard Google shape: read candidates[0].content.parts and join the text parts. The same JSON carries usageMetadata with prompt, candidate and total token counts, so token- and cost-tracking code works from the very first call.
Before sending a large prompt, call :countTokens on the same model path. It returns a token count without generating anything — a free input estimate before you spend on generation.
Stream tokens with streamGenerateContent
curl "https://router.apitoken.sale/v1beta/models/gemini-3.6-flash:streamGenerateContent?alt=sse" \
-H "x-goog-api-key: $APITOKEN_API_KEY" \
-H "Content-Type: application/json" \
-d '{"contents":[{"parts":[{"text":"Count from one to five"}]}]}'The ?alt=sse query switches the response to server-sent events: each event is one incremental chunk in the same candidate structure, and the terminal event carries the aggregate usageMetadata. In the SDKs the same route is reached through generate_content_stream in Python and generateContentStream in JavaScript.
Stream anything user-facing so the first tokens render immediately. For batch jobs where only the final text matters, plain generateContent is simpler to parse and retry.
Official SDKs: Python and JavaScript
import os
from google import genai
from google.genai import types
client = genai.Client(
api_key=os.environ["APITOKEN_API_KEY"],
http_options=types.HttpOptions(base_url="https://router.apitoken.sale"),
)
response = client.models.generate_content(
model="gemini-3.6-flash",
contents="Reply with exactly: connected",
)
print(response.text)import { GoogleGenAI } from "@google/genai";
const ai = new GoogleGenAI({
apiKey: process.env.APITOKEN_API_KEY,
httpOptions: { baseUrl: "https://router.apitoken.sale" },
});
const response = await ai.models.generateContent({
model: "gemini-3.6-flash",
contents: "Reply with exactly: connected",
});
console.log(response.text);- Pass the bare base URL https://router.apitoken.sale; do not append /v1beta in SDK configuration.
- Pass a concrete model ID such as gemini-3.6-flash — never rely on a client default.
- Keep APITOKEN_API_KEY in the environment rather than in source code.
If every SDK request returns 404, check the request path for a doubled /v1beta/v1beta segment. The SDK appends its API version itself; configuring the host with /v1beta already included produces the doubled path.
What the first calls cost
Gemini calls settle at the exact official Google rate legs — input, cached input and output — and the flat 50% discount is applied on top. Post-discount prices per 1M tokens for the common text models:
| Model | Input / cached / output per 1M | Good first job |
|---|---|---|
| gemini-3.6-flash | $0.375 / $0.0375 / $1.875 | Everyday coding, chat and agents |
| gemini-3.1-flash-lite | $0.125 / $0.0125 / $0.75 | Classification, extraction, routing |
| gemini-2.5-flash-lite | $0.05 / $0.005 / $0.20 | Cheapest high-volume text |
| gemini-3.1-pro-preview | $1 / $0.10 / $6 | Hardest reasoning and review |
Troubleshooting the first response
| Status | Likely cause | Fix |
|---|---|---|
| 400 | Missing or wrong x-goog-api-key (INVALID_ARGUMENT, reason API_KEY_INVALID), or a field this endpoint cannot honour (FILE_URI_UNSUPPORTED / CACHED_CONTENT_UNSUPPORTED) | Re-check the key and header; send files as inlineData; omit cachedContent |
| 404 | Doubled /v1beta, or a model ID not in the catalog | Pass the bare host; pick an ID from GET /v1beta/models |
| 402 FAILED_PRECONDITION | Prepaid balance exhausted — HTTP 402, not RESOURCE_EXHAUSTED and not 429 | Top up any whole-dollar amount in the dashboard |
Do not send Authorization: Bearer or the Anthropic x-api-key header on the native Gemini routes — x-goog-api-key is the only credential they accept. Because the wire format is unchanged, reverting to Google's own endpoint later is a one-line base-URL change.
Frequently asked questions
Does the official Google GenAI SDK work with apiToken.sale?
Yes. Set HttpOptions(base_url) in Python or httpOptions.baseUrl in JavaScript to https://router.apitoken.sale and pass the apiToken.sale key; request and response shapes stay native.
Which header authenticates Gemini API requests?
x-goog-api-key carrying your sk-pool key. The native Gemini routes do not accept Authorization: Bearer or the Anthropic x-api-key header.
How do I stream Gemini output?
Call /v1beta/models/{model}:streamGenerateContent?alt=sse with x-goog-api-key, or use the SDK's generate_content_stream / generateContentStream method. The terminal SSE event carries the aggregate usageMetadata.
Why does a doubled /v1beta return 404?
The Google SDK appends its API version to the configured host. Configure only the bare host so the final request contains exactly one /v1beta segment.
Which Gemini model should I call first?
Start with gemini-3.6-flash for general text and coding work. Move bulk classification to a Flash-Lite model and the hardest reasoning to gemini-3.1-pro-preview.
Is countTokens free to call?
Yes. Calling :countTokens on the model path returns a token count without generating, so you can estimate input size before paying for a generation.
Create an account, top up your balance, and generate an API key to use supported Claude, GPT and Gemini models.