How to Resolve HTTP 401 Errors When Calling Gemini with an API Key
Date: 2026-09-02
Target Audience: Users encountering 401 / UNAUTHENTICATED when calling Gemini (including gemini-3.7-flash) via an API key, or those needing to distinguish between 401, 403, and 400 errors.
Example Model: gemini-3.7-flash (GA)
SDK: google-genai (Python)
Scope and Methodology (to distinguish between official documentation and same-day verification):
| Scope | Basis |
|---|---|
Sections 3–6, gemini-3.7-flash text |
Cross-verified on 2026-09-02 using a Gemini API–bound AQ. key, an Agent Platform–bound AQ. key, and an AI Studio AIza key. |
| Section 7: Standard / Auth Key policy | Official Gemini API Key documentation (unrestricted Standard Keys restricted starting 2026-06); not re-tested against 9/2 policies. |
| Community report: “Deprecated model masquerading as 401” | Isolated cases reported in public forums; testing gemini-2.5-flash with the same AQ. key on 9/2 did not reproduce a 401 (returned 200). |
The SDK determines the gateway based on the explicit parameters passed to Client(...). If GOOGLE_GENAI_USE_VERTEXAI or GOOGLE_API_KEY / GEMINI_API_KEY environment variables are also set, the runtime behavior may diverge from what the code implies. During debugging, explicitly hardcode vertexai=True or api_key=; do not rely on implicit environment variable routing.
Table of Contents
- Summary of Conclusions
- First, Confirm Whether It Is Truly a 401 (401 vs. 403 vs. 400)
- Correct Ways to Pass the API Key
- Matching the Error by
reason - Verified 401 Scenarios and Fixes
- If It Is Not a 401, Do Not Modify Authentication Headers According to This Guide
- Appendix:
AQ.vs.AIza, Standard Key Policy - Appendix: OpenAI Compatibility Layer
- Integration Checklist
- Minimal Self-Test
- Related Documentation
1. Summary of Conclusions
A 401 UNAUTHENTICATED error fundamentally means that the gateway rejected the provided credentials. The model has not begun inference, nor does it mean gemini-3.7-flash is unavailable.
Benchmark test on 2026-09-02: Calling gemini-3.7-flash with an AQ. key bound to the Gemini API via ?key=, x-goog-api-key, or Client(api_key=...) (without vertexai=True) consistently returned HTTP 200. Once the exact same key was sent as Authorization: Bearer to the native generateContent endpoint, it immediately resulted in a 401.
A 401 error is rarely caused by an “expired key” or “deprecated model”; it typically falls into one of the following three categories:
| Actual Configuration | Typical HTTP Status | Typical reason |
Solution |
|---|---|---|---|
Native Gemini / Agent Platform REST requests using OpenAI-style Authorization: Bearer <API Key> |
401 | API_KEY_SERVICE_BLOCKED or ACCESS_TOKEN_TYPE_UNSUPPORTED |
Change how the key is passed: For native endpoints, use ?key= or x-goog-api-key; do not use Bearer. |
The AQ. key is invalid, truncated, or missing characters from copying |
401 | ACCESS_TOKEN_TYPE_UNSUPPORTED |
Verify the complete key string. Do not let the message “Expected OAuth 2 access token” mislead you into switching to OAuth. |
Using an AIza key (AI Studio Standard Key) to call Agent Platform / vertexai=True |
401 | CREDENTIALS_MISSING |
In production, use an Agent Platform Key + vertexai=True; or remove vertexai=True and route requests through the Gemini API. |
Do not start by changing the model ID or rotating the key. First, inspect the HTTP status code and details[].reason, then verify the request domain and how the key is transmitted.
For production environments, using Agent Platform is recommended (either with an Agent Platform API–bound key or service account ADC). If you must use the Gemini Developer API, strictly use ?key=, x-goog-api-key, or Client(api_key=...), and never place an API key into Authorization: Bearer.
2. First, Confirm Whether It Is Truly a 401 (401 vs. 403 vs. 400)
A common mistake is confusing a 403 or 400 with a 401. The fixes for these three errors are entirely different. Always rely on error.code in the JSON response, rather than the generic summary string provided by the SDK wrapper.
error.code |
status |
Meaning | Covered in this guide? | Where to look |
|---|---|---|---|---|
| 401 | UNAUTHENTICATED |
The gateway does not recognize a valid identity | Yes | Sections 4 & 5 |
| 403 | PERMISSION_DENIED |
Identity recognized, but the key is not permitted to access this gateway / method | No | 403 Guide |
| 400 | INVALID_ARGUMENT with reason: API_KEY_INVALID |
Invalid AIza key, leftover quotation marks, or revoked key |
Reference | Section 6.2; not a 401 |
A frequent point of confusion: reason: API_KEY_SERVICE_BLOCKED can appear in both 401 and 403 responses.
| HTTP Status | Shared reason |
Actual Meaning | Solution |
|---|---|---|---|
401 + API_KEY_SERVICE_BLOCKED |
The gateway treated this request as OAuth (usually because Authorization: Bearer was passed), and an API key cannot serve as an access token |
Remove the Bearer header and use x-goog-api-key or ?key= instead. |
|
403 + API_KEY_SERVICE_BLOCKED |
The key is valid, but bound to a different API | Align the key binding with the gateway; refer to the 403 Guide. |
Always inspect error.code before checking reason. Do not search for API_KEY_SERVICE_BLOCKED in isolation.
First, extract these five fields from the full error JSON (remember to mask keys in logs):
error.code
error.status
error.message
error.details[].reason
error.details[].metadata.service (generativelanguage vs. aiplatform)
error.details[].metadata.methodName
Then verify three details:
- Target domain:
generativelanguage.googleapis.com,aiplatform.googleapis.com, or the OpenAI compatibility path/v1beta/openai/... - Transmission method:
?key=,x-goog-api-key, orAuthorization: Bearer - Key prefix:
AQ.orAIza(never write full keys into logs or screenshots)
3. Correct Ways to Pass the API Key
There are two product families and three authentication approaches. Using the wrong authentication header will result in a 401; targeting the wrong gateway will result in a 403.
3.1 Comparison Table
| Product | Key Binding | Gateway | Correct Method | Incorrect (Yields 401 or 403) |
|---|---|---|---|---|
| Gemini API (Developer / Prototyping) | Gemini API | generativelanguage.googleapis.com |
?key= or header x-goog-api-key; SDK Client(api_key=...) |
Calling native generateContent with Authorization: Bearer <API Key> → 401 |
| Agent Platform Express (Recommended for Production · API Key) | Agent Platform API | aiplatform.googleapis.com |
?key= or x-goog-api-key; SDK Client(vertexai=True, api_key=...) |
Authorization: Bearer <API Key> → 401; Key bound to Gemini API targeting this URL → 403 |
| Agent Platform ADC (Recommended for Production · Service Account) | Service Account / User ADC | aiplatform.googleapis.com |
OAuth access token (handled automatically by SDK) | Passing an API key inside Authorization: Bearer |
| Gemini OpenAI Compatibility Layer | Gemini API | generativelanguage.googleapis.com/v1beta/openai/... |
Must use Authorization: Bearer <Gemini API Key> |
Passing only x-goog-api-key without an Authorization header → 400 Missing Authorization header |
The required authentication headers for native Gemini generateContent and the OpenAI compatibility layer are exact opposites:
native :generateContent → ?key= or x-goog-api-key (do NOT use Bearer)
OpenAI-compatible /v1beta/openai → Authorization: Bearer (do NOT provide only x-goog-api-key)
3.2 Correct Syntax for Gemini API
SDK:
from google import genai
client = genai.Client(api_key="YOUR_GEMINI_API_KEY") # Do NOT set vertexai=True
response = client.models.generate_content(
model="gemini-3.7-flash",
contents="Reply with OK only.",
)
print(response.text)
REST (Header is recommended to prevent keys from leaking into URL logs):
curl -X POST \
"https://generativelanguage.googleapis.com/v1beta/models/gemini-3.7-flash:generateContent" \
-H "Content-Type: application/json" \
-H "x-goog-api-key: YOUR_GEMINI_API_KEY" \
-d '{
"contents": [
{"role": "user", "parts": [{"text": "Reply with OK only."}]}
]
}'
Equivalent: ...:generateContent?key=YOUR_GEMINI_API_KEY (do not add an Authorization header).
Verified (2026-09-02): Using an AQ. key bound to the Gemini API, all three approaches (?key=, x-goog-api-key, and the SDK) calling gemini-3.7-flash returned HTTP 200.
3.3 Correct Syntax for Agent Platform
from google import genai
client = genai.Client(
vertexai=True,
api_key="YOUR_AGENT_PLATFORM_API_KEY",
)
response = client.models.generate_content(
model="gemini-3.7-flash",
contents="Reply with OK only.",
)
print(response.text)
REST:
curl -X POST \
"https://aiplatform.googleapis.com/v1/publishers/google/models/gemini-3.7-flash:generateContent?key=YOUR_AGENT_PLATFORM_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"contents": [
{"role": "user", "parts": [{"text": "Reply with OK only."}]}
]
}'
This key must be restricted to Agent Platform API in Studio Restrictions. Sending a Gemini API–bound key to this URL returns 403, not 401.
In production, service account ADC is preferred (vertexai=True + project / location, omitting api_key). A 401 in an ADC workflow usually indicates an expired OAuth token or missing ADC configuration; troubleshoot these following standard Google Cloud authentication practices rather than this API key guide.
4. Matching the Error by reason
When receiving a 401, first check details[].reason (or check message if reason is absent).
reason |
Observed message Excerpt |
Root Cause | Solution |
|---|---|---|---|
ACCESS_TOKEN_TYPE_UNSUPPORTED |
Expected OAuth 2 access token… | 1. Invalid or truncated AQ. key; 2. Passed an AIza key as Bearer to native endpoints |
1. Verify the complete AQ. key string; 2. Switch to x-goog-api-key for native endpoints |
API_KEY_SERVICE_BLOCKED (with HTTP 401) |
Expected OAuth 2 access token… or API keys are not supported… Expected OAuth2 | Used Authorization: Bearer <API Key> with native / Agent Platform REST, or sent both ?key= and Bearer simultaneously |
Remove Bearer; keep only ?key= or x-goog-api-key |
CREDENTIALS_MISSING |
API keys are not supported by this API. Expected OAuth2 access token… | Sent an AIza key to aiplatform.googleapis.com, or configured SDK with vertexai=True, api_key=AIza... |
In production, replace with an Agent Platform key; or remove vertexai=True to use the Gemini API |
| (No reason, only 401 UNAUTHENTICATED) | Matches one of the three message patterns above | reason might be stripped by SDK error wrapping |
Inspect the raw error JSON and match by message using the rows above |
Seeing Expected OAuth 2 access token in the message does not necessarily mean you need to implement OAuth. When using API keys, this simply indicates: The current request was interpreted as an OAuth request, so the API key was not accepted as a valid token. Fix the authentication header first; do not immediately switch to service accounts.
5. Verified 401 Scenarios and Fixes
All examples below were tested against gemini-3.7-flash on 2026-09-02. Correct configurations returned 200; misconfigurations were blocked at the gateway.
5.1 Passing Authorization: Bearer <API Key> to Native generateContent (Most Common)
Scenario: You have a valid Gemini API key (AQ.).
What went wrong: You copied Authorization: Bearer from an OpenAI sample or web tutorial, but targeted the native Gemini endpoint.
# INCORRECT: Native generateContent does not accept API keys as Bearer tokens
curl -X POST \
"https://generativelanguage.googleapis.com/v1beta/models/gemini-3.7-flash:generateContent" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_GEMINI_API_KEY" \
-d '{"contents":[{"role":"user","parts":[{"text":"Reply with OK only."}]}]}'
Test result: HTTP 401. reason is API_KEY_SERVICE_BLOCKED (Note: This is a 401, not the gateway mismatch covered in the 403 guide):
{
"error": {
"code": 401,
"message": "Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
"status": "UNAUTHENTICATED",
"details": [{
"@type": "type.googleapis.com/google.rpc.ErrorInfo",
"reason": "API_KEY_SERVICE_BLOCKED",
"metadata": {
"service": "generativelanguage.googleapis.com",
"methodName": "google.ai.generativelanguage.v1beta.GenerativeService.GenerateContent"
}
}]
}
}
Passing an AIza key as Bearer to the native endpoint similarly yields 401, though reason becomes ACCESS_TOKEN_TYPE_UNSUPPORTED while message still states “Expected OAuth 2 access token”.
Solution: Keep the key, but change how it is sent:
curl -X POST \
"https://generativelanguage.googleapis.com/v1beta/models/gemini-3.7-flash:generateContent" \
-H "Content-Type: application/json" \
-H "x-goog-api-key: YOUR_GEMINI_API_KEY" \
-d '{"contents":[{"role":"user","parts":[{"text":"Reply with OK only."}]}]}'
Only retain Authorization: Bearer if your application explicitly targets the OpenAI-compatible URL (path containing /v1beta/openai/), as detailed in Section 8.
5.2 Sending Both ?key= and Authorization: Bearer Simultaneously
Gateways, SDKs, reverse proxies, or middleware often automatically inject a Bearer header while the URL query string already contains ?key=.
# INCORRECT: Transmitting conflicting credentials simultaneously
curl -X POST \
"https://generativelanguage.googleapis.com/v1beta/models/gemini-3.7-flash:generateContent?key=YOUR_GEMINI_API_KEY" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_GEMINI_API_KEY" \
-d '{"contents":[{"role":"user","parts":[{"text":"ping"}]}]}'
Test result: HTTP 401, reason: API_KEY_SERVICE_BLOCKED:
{
"error": {
"code": 401,
"message": "API keys are not supported by this API. Expected OAuth2 access token or other authentication credentials that assert a principal. See https://cloud.google.com/docs/authentication",
"status": "UNAUTHENTICATED"
}
}
Solution: Keep only one transmission method for native requests: ?key= or x-goog-api-key. Verify whether default headers in your HTTP client, API gateway, or orchestration frameworks (LangChain, Dify, custom proxies) are forcing an Authorization header injection.
5.3 Invalid or Truncated AQ. Key
Scenario: The key string starts with AQ., but is not the complete key from the console (due to copy-paste truncation, line breaks in .env, secrets manager limits, or leftover placeholders).
When a string looks structurally like an AQ. key, Gemini native REST will not return API_KEY_INVALID; instead, it produces a 401 error message resembling an OAuth format failure:
Test result (with forged or truncated AQ. key): HTTP 401, reason: ACCESS_TOKEN_TYPE_UNSUPPORTED:
{
"error": {
"code": 401,
"message": "Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential.",
"status": "UNAUTHENTICATED",
"details": [{
"reason": "ACCESS_TOKEN_TYPE_UNSUPPORTED",
"metadata": {
"service": "generativelanguage.googleapis.com",
"methodName": "google.ai.generativelanguage.v1beta.GenerativeService.GenerateContent"
}
}]
}
}
This is the easiest scenario to misdiagnose: The error complains about an invalid token type, but the actual cause is a corrupted key string.
Solution:
- Visit Studio API keys, confirm that Restrictions is set to Gemini API, and re-copy the full key.
- Strip leading/trailing whitespace, newlines, and stray JSON quotes. While whitespace around
x-goog-api-keyis trimmed by the server (returning 200), extra quotes cause a distinct error (see Section 6.2). - Validate using the minimal curl command in Section 10. Once it succeeds with HTTP 200, check whether your application code is truncating the value.
- Do not switch to ADC simply because OAuth was mentioned in the error message.
An invalid AIza key produces 400 API_KEY_INVALID instead. Different key prefixes trigger different error codes.
5.4 Using an AIza Key Against Agent Platform / vertexai=True
Scenario: You have an AIza-prefixed key created in AI Studio.
What went wrong: You added vertexai=True based on Agent Platform / Express examples, or targeted aiplatform.googleapis.com via REST.
from google import genai
# INCORRECT: An AIza key is not valid for Agent Platform Express
client = genai.Client(
vertexai=True,
api_key="AIzaSy.....",
)
client.models.generate_content(model="gemini-3.7-flash", contents="Reply with OK only.")
Equivalent REST error: https://aiplatform.googleapis.com/v1/publishers/google/models/gemini-3.7-flash:generateContent?key=AIza...
Test result: HTTP 401, reason: CREDENTIALS_MISSING:
{
"error": {
"code": 401,
"message": "API keys are not supported by this API. Expected OAuth2 access token or other authentication credentials that assert a principal. See https://cloud.google.com/docs/authentication",
"status": "UNAUTHENTICATED",
"details": [{
"reason": "CREDENTIALS_MISSING",
"metadata": {
"service": "aiplatform.googleapis.com",
"methodName": "google.cloud.aiplatform.v1.PredictionService.GenerateContent"
}
}]
}
}
SDK wrappers typically summarize this as: 401 UNAUTHENTICATED. {'error': {'code': 401, 'message': 'API keys are not supported by this API. ...', 'reason': 'CREDENTIALS_MISSING'}}.
Fix for production: Navigate to Studio, create an API key bound to Agent Platform API, and retain vertexai=True. Do not treat AI Studio AIza keys as Express keys.
If you must use Gemini API: Remove vertexai=True to route requests back to generativelanguage.googleapis.com. Also verify that the AIza key is still active (an invalid key produces a 400 error as covered in Section 6.2).
5.5 Passing an API Key as Bearer to Agent Platform REST
This is identical to Section 5.1, but targets aiplatform.googleapis.com. Express API keys must also be transmitted via ?key= or x-goog-api-key, and cannot be supplied as OAuth Bearer tokens.
Test result: HTTP 401, reason: API_KEY_SERVICE_BLOCKED, service: aiplatform.googleapis.com, with the message still stating “Expected OAuth 2 access token”.
Solution: Follow the REST example in Section 3.3. If your production environment mandates Bearer authentication, you must use ADC / OAuth access tokens rather than raw API key strings.
5.6 Empirical Comparison Matrix (gemini-3.7-flash, 2026-09-02)
| Key | Transmission Method | Result |
|---|---|---|
Gemini API–bound AQ. |
?key= / x-goog-api-key / Client(api_key=...) |
|
Gemini API–bound AQ. |
native + Authorization: Bearer |
API_KEY_SERVICE_BLOCKED |
Gemini API–bound AQ. |
?key= and Authorization: Bearer |
API_KEY_SERVICE_BLOCKED |
Gemini API–bound AQ. |
OpenAI-compatible + Authorization: Bearer |
|
Gemini API–bound AQ. |
OpenAI-compatible + x-goog-api-key only |
|
Forged / truncated AQ. |
native ?key= |
ACCESS_TOKEN_TYPE_UNSUPPORTED |
AIza (Invalid) |
native ?key= |
API_KEY_INVALID (not 401) |
AIza |
native + Bearer | ACCESS_TOKEN_TYPE_UNSUPPORTED |
AIza |
Agent Platform Express / vertexai=True |
CREDENTIALS_MISSING |
Agent Platform–bound AQ. |
Gemini API native | API_KEY_SERVICE_BLOCKED |
Gemini API–bound AQ. |
Agent Platform Express ?key= |
API_KEY_SERVICE_BLOCKED |
| No Key provided | native | |
Gemini API–bound AQ. |
gemini-2.5-flash / gemini-3.6-flash native |
6. If It Is Not a 401, Do Not Modify Authentication Headers According to This Guide
6.1 403 API_KEY_SERVICE_BLOCKED: Gateway and Key Mismatch
HTTP 403, PERMISSION_DENIED, Requests to this API … are blocked.
This occurs when the API binding on the key does not match the target gateway, not because of malformed authentication headers. See the 403 Guide for details:
- Key bound to Agent Platform → Must use
vertexai=True/aiplatform.googleapis.com - Key bound to Gemini API → Must use
Client(api_key=...)/generativelanguage.googleapis.com
Do not attempt to fix 403 errors by modifying Bearer headers, and do not rotate keys prematurely.
6.2 400 API_KEY_INVALID: Invalid AIza Key or Stray Quotes
Test result: Passing an invalid AIza key or one enclosed in literal quotes (") to Gemini native REST yields 400 (not 401):
{
"error": {
"code": 400,
"message": "API key not valid. Please pass a valid API key.",
"status": "INVALID_ARGUMENT",
"details": [{
"reason": "API_KEY_INVALID",
"metadata": {
"service": "generativelanguage.googleapis.com"
}
}]
}
}
Solution: Strip quotes and whitespace, then confirm the key is active in AI Studio API keys; alternatively, create a new AQ. Auth Key in Studio. Do not attempt OAuth-related fixes for this error.
6.3 403 unregistered callers: No Key Provided in Request
Test result: Calling native generateContent without credentials returns 403:
Method doesn't allow unregistered callers (callers without established identity).
Please use API Key or other form of API consumer identity to call this API.
Solution: Add x-goog-api-key or ?key=. Ensure the necessary environment variables are properly injected into your runtime environment (containers, CI pipelines, API gateways).
6.4 Model ID / Parameter Errors
Supplying unsupported parameters such as an invalid thinking_level (e.g., MINIMAL) results in a 400, unrelated to 401 errors. Refer to Section 8 of the 403 Guide for 3.7 Flash parameter requirements.
Community forums have reported instances of deprecated models returning 401 ACCESS_TOKEN_TYPE_UNSUPPORTED. However, calling gemini-2.5-flash with a valid AQ. key on 2026-09-02 returned HTTP 200. Do not assume a 401 is caused by model deprecation by default. Check your authentication format and key integrity as described in Section 5 first.
7. Appendix: AQ. vs. AIza, Standard Key Policy
| Prefix | Common Source | Details |
|---|---|---|
AQ. |
Agent Platform Studio; newer AI Studio Auth Keys | The prefix alone does not reveal whether the key is bound to the Agent Platform API or the Gemini API; verify this in console Restrictions. |
AIza |
Legacy AI Studio / Google Cloud Standard API Keys | Can only access the Gemini Developer API; cannot be used as an Agent Platform Express Key (doing so results in the 401 error described in Section 5.4). |
Official policy (Gemini API Key Documentation, not 9/2 live tests):
- Newly created AI Studio keys default to Auth Keys (
AQ.). - Starting 2026-06-19, the Gemini API rejects unrestricted Standard Keys.
- Starting September 2026, all Standard Keys are scheduled for deprecation, requiring migration to Auth Keys.
If you are still using a legacy AIza key: Verify whether it still returns 200 on native Gemini endpoints. If it fails, treat it as a 400 API_KEY_INVALID and migrate to an AQ. Auth Key. After migrating, ensure you follow the key transmission formats in Section 3; otherwise, your 400 error may simply turn into a 401.
8. Appendix: OpenAI Compatibility Layer
Path format:
https://generativelanguage.googleapis.com/v1beta/openai/chat/completions
This endpoint uses a different authentication scheme than the native :generateContent endpoint.
| Syntax | Verified on 2026-09-02 (Gemini API–bound AQ. key + gemini-3.7-flash) |
|---|---|
Authorization: Bearer <Gemini API Key> |
|
Sent only x-goog-api-key, omitted Authorization |
Missing or invalid Authorization header. |
Keep in mind the inverted authentication requirements for these endpoints:
- Path contains
/openai/→ Use Bearer; do not send onlyx-goog-api-key. - Path contains
:generateContent→ Usex-goog-api-keyor?key=; do not use Bearer. - If the same valid key returns 200 on one endpoint but 401 on another, verify whether paths and headers are crossed before attempting to rotate the key.
Certain third-party clients force AQ. keys into OpenAI SDKs while simultaneously appending key= query parameters, which may trigger 400 Multiple authentication credentials received (reported in official forums, not evaluated in this test matrix). The fix remains the same: supply credentials using only one method.
9. Integration Checklist
Follow these steps in sequence. Draw conclusions at each step before making further adjustments; do not change the model, key, and region at the same time.
- Inspect the full error JSON and record
code,status,reason,service, andmethodName. - Check the HTTP status code: For 401, follow Sections 4 and 5 of this guide; for 403, refer to the 403 Guide; for 400
API_KEY_INVALID, see Section 6.2. - Verify the request domain:
generativelanguage(Gemini API),aiplatform(Agent Platform), or/v1beta/openai/. - Check the key transmission method: Are the actual headers sending
Authorization: Bearer,?key=, orx-goog-api-key? Are multiple credentials being sent at the same time? - Check key prefix and restrictions: Is it
AQ.orAIza? Is Studio Restrictions configured for Agent Platform API or Gemini API? - Inspect SDK configuration: Is
vertexai=Trueset? Are environment variables likeGOOGLE_GENAI_USE_VERTEXAI,GOOGLE_API_KEY, orGEMINI_API_KEYdefined? - Run the minimal test in Section 10 using the same key. If the minimal test returns 200 but application code throws 401, the issue lies in application-level headers, proxy middleware, or duplicate credentials. If the minimal test also fails with 401, address the key or gateway mapping based on the
reasonin Section 4. - Prefer Agent Platform for production workloads; migrate to ADC prior to full launch.
Recommended verification checklist:
| Item | Expected Value |
|---|---|
error.code / details.reason |
Follow this guide only if the error is 401; see respective sections for 403 / 400 |
| Request URL | One of generativelanguage, aiplatform, or /openai/ |
| Auth header | Native requests only use ?key= or x-goog-api-key; Bearer is reserved for the OpenAI compatibility layer |
| API key | Prefixed with AQ. or AIza; Restrictions match the target gateway |
| SDK parameters | vertexai=True targets Agent Platform; api_key= alone targets Gemini API |
10. Minimal Self-Test
Replace the placeholder keys in the snippets below with your own. Run Test A first, then consult Tests B and C to analyze any failures.
A. Correct Gemini API Path (Expected: 200)
curl -sS -X POST \
"https://generativelanguage.googleapis.com/v1beta/models/gemini-3.7-flash:generateContent" \
-H "Content-Type: application/json" \
-H "x-goog-api-key: YOUR_GEMINI_API_KEY" \
-d '{"contents":[{"role":"user","parts":[{"text":"Reply with OK only."}]}]}'
from google import genai
client = genai.Client(api_key="YOUR_GEMINI_API_KEY")
print(client.models.generate_content(model="gemini-3.7-flash", contents="Reply with OK only.").text)
B. Reproducing 401: Switching the Same Key to Bearer (Expected: 401)
curl -sS -X POST \
"https://generativelanguage.googleapis.com/v1beta/models/gemini-3.7-flash:generateContent" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_GEMINI_API_KEY" \
-d '{"contents":[{"role":"user","parts":[{"text":"Reply with OK only."}]}]}'
If Test A succeeds and Test B yields 401, the key is completely functional; the issue was treating the API key as an OAuth Bearer token. Revert your headers to match Test A as described in Section 5.1.
C. Correct Agent Platform Path (Expected: 200)
from google import genai
client = genai.Client(vertexai=True, api_key="YOUR_AGENT_PLATFORM_API_KEY")
print(client.models.generate_content(model="gemini-3.7-flash", contents="Reply with OK only.").text)
If you run Test C with an AIza key, expect a 401 CREDENTIALS_MISSING error (Section 5.4). Replace it with an Agent Platform API–bound key; do not alter the model parameter.
11. Related Documentation
- Companion Guide: Resolving 403 errors caused by key/gateway mismatches: How to Resolve HTTP 403 Errors When Calling Gemini with an API Key
- Create API Keys: https://console.cloud.google.com/agent-platform/studio/settings/api-keys
- AI Studio API Keys: https://aistudio.google.com/api-keys
- Gemini API Key Overview (Auth Keys vs. Standard Keys): https://ai.google.dev/gemini-api/docs/api-key
- Getting Started with Agent Platform: Get started with Gemini Enterprise Agent Platform | Google Cloud Documentation
- Express Mode SDK: Tutorial: Agent Platform API in express mode | Gemini Enterprise Agent Platform | Google Cloud Documentation
- Gemini 3.7 Flash: Gemini 3.7 Flash | Gemini Enterprise Agent Platform | Google Cloud Documentation
- OpenAI Compatibility: https://ai.google.dev/gemini-api/docs/openai
- Google Cloud Authentication Overview: Authentication for Google Cloud APIs and services | Google Cloud Documentation