A Gemini generateContent request has three essential pieces: a model endpoint, authentication, and a JSON body containing your input. This first-request lap builds a text-only call from scratch, then adds the response handling and troubleshooting checks you need before putting it inside an application.
1. Choose the Gemini endpoint and model
Start with Gemini 2.5 Flash for this walkthrough. Its API identifier is gemini-2.5-flash. The native Google endpoint is https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent.
The model identifier belongs in the URL. The generateContent suffix selects the operation. This is a regular request-response call, not a streaming request, so your client receives a JSON response after generation finishes.
Keep native Gemini requests separate from OpenAI-compatible requests. Their routes, authentication conventions, and message formats are not interchangeable.
2. Store the API key outside your request body
Create a Gemini API key through Google AI Studio, then make it available to your terminal:
export GEMINI_API_KEY='YOUR_API_KEY'
This command works in common Unix-style shells. Replace the placeholder locally, and never paste the resulting key into an issue, screenshot, or committed source file. Environment variables are convenient for a local test; deployed applications should use their platform's secret-management facilities.
The direct Google request below sends that key through the x-goog-api-key header. Authentication does not belong inside contents.
3. Build the contents and parts structure
The request body needs a contents array. Each entry represents a conversation turn, and each turn contains a parts array. For a text-only request, a part contains a text field.
{"contents":[{"role":"user","parts":[{"text":"Write three practical checks before deploying an API client."}]}]}
The explicit user role makes the turn easy to understand. Keeping parts as an array also leaves room for supported multimodal inputs later. For this first call, avoid extra fields until the smallest useful request succeeds.
4. Send the complete generateContent request
Run this command in the same terminal where you exported the key:
curl --fail-with-body 'https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent' -H "x-goog-api-key: $GEMINI_API_KEY" -H 'Content-Type: application/json' --data '{"contents":[{"role":"user","parts":[{"text":"Write three practical checks before deploying an API client."}]}],"generationConfig":{"maxOutputTokens":512}}'
The data argument makes this a POST request. Content-Type tells the server to interpret the payload as JSON. The generationConfig object limits output tokens, but it does not guarantee a particular word count or a complete answer within that limit.
If your curl version does not support --fail-with-body, remove that option and inspect the HTTP status separately.
5. Extract text without assuming every response matches
Generated output normally appears under candidates[0].content.parts. Read the text-bearing parts in order rather than assuming the first part always contains the complete answer.
- Check that candidates exists and contains an entry before indexing it.
- Inspect finishReason to understand whether generation completed or stopped at a limit.
- Inspect promptFeedback when the prompt is blocked or no candidate is returned.
- Record usageMetadata when available to track token consumption.
In application code, keep HTTP error handling separate from successful-response parsing. An error payload should not be treated as an empty model answer.
6. Add conversation history explicitly
A plain generateContent request does not automatically remember your previous call. For a follow-up, send the earlier user turn, the returned model turn, and the new user turn in the contents array.
Use model as the role for the generated reply, not assistant. Preserve the returned content structure when assembling history. As conversations grow, trim or summarize older turns deliberately rather than letting request size grow without a boundary.
7. Check routing and failures before your next lap
For authentication failures, check the key and its restrictions. For malformed requests, check JSON syntax and field placement. For rate-limit or transient server errors, use bounded retries with backoff; do not repeatedly retry invalid credentials or invalid payloads.
SwiftRelay is a practical pay-as-you-go option when you want token-based billing across providers. Sign up for SwiftRelay to try it with the small gift credit available to new accounts. Its API host is https://api.fastapirelay.com; confirm its Gemini-native route and authentication requirements before adapting this direct Google example. Do not automatically append /v1 or reuse Google's authentication header merely because another integration uses them.