Vercel AI Gateway API key returns 403 Forbidden despite valid setup

Hi Vercel team,

We seem to be running into the same kind of AI Gateway 403 issue discussed in the earlier community thread: Resolving 403 Forbidden error for Vercel AI Gateway API keys
Our setup is using the OpenAI-compatible AI Gateway endpoint: https://ai-gateway.vercel.sh/v1
Requests are sent with an AI Gateway API key via Authorization: Bearer [key], and the model is routed as xai/grok-4.3.
The request is rejected with 403 Forbidden / access_denied. From the earlier thread, it sounded like some cases were caused by account/team entitlement or billing/card validation issues that had to be fixed internally by Vercel.
The project/account identifier is storypalse-7526.
Could someone from Vercel check whether this project/account has the same AI Gateway entitlement or billing validation issue? I can provide any additional team/account details privately if needed.
Thanks!

@anshumanb hello, it’s happened again..

Hi Storypalse,

I can’t check the account/team state from here, but I’d separate a config problem from a Gateway/account-side problem with one very small test using the same key.

First, try listing models with the exact same environment variable:

curl -i "https://ai-gateway.vercel.sh/v1/models" \
  -H "Authorization: Bearer $AI_GATEWAY_API_KEY"

If that also returns 403 access_denied, then the request is probably not reaching the model step at all. I’d check that the key is an AI Gateway API key from the same Vercel team/project context you expect, not a provider key or a general Vercel token. I’d also try creating a fresh AI Gateway key and testing it locally before changing app code.

If /v1/models works, then the key itself is probably accepted and I’d narrow it to the model request. Since you’re using xai/grok-4.3, I’d verify that exact model ID appears in the returned models list, then test with a known working model from that list:

curl -i "https://ai-gateway.vercel.sh/v1/chat/completions" \
  -H "Authorization: Bearer $AI_GATEWAY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai/gpt-5.4",
    "messages": [{ "role": "user", "content": "test" }],
    "stream": false
  }'

If /v1/models is fine but only the xAI model fails, that points more toward model availability/provider routing than the API key itself. If every model returns 403 with a fresh Gateway key, then staff probably do need to inspect the workspace/account state.

Can you share the status code and redacted response body from the /v1/models test?

Thanks. I tested with the same AI_GATEWAY_API_KEY.

GET /v1/models succeeds:

  • status: 200
  • model count: 282
  • xai/grok-4.3 is present
  • openai/gpt-5.4 is present

But POST /v1/chat/completions returns 403 for both models:

xai/grok-4.3:
{“error”:{“message”:“Forbidden.”,“type”:“access_denied”}}

openai/gpt-5.4:
{“error”:{“message”:“Forbidden.”,“type”:“access_denied”}}

So the key appears to be accepted for model listing, and the model IDs are available, but inference requests are forbidden across models. This looks more like an account/workspace entitlement or billing validation issue than a config/model ID issue.

Thanks. I tested with the same AI_GATEWAY_API_KEY.

GET /v1/models succeeds:

  • status: 200
  • model count: 282
  • xai/grok-4.3 is present
  • openai/gpt-5.4 is present

But POST /v1/chat/completions returns 403 for both models:

xai/grok-4.3:
{“error”:{“message”:“Forbidden.”,“type”:“access_denied”}}

openai/gpt-5.4:
{“error”:{“message”:“Forbidden.”,“type”:“access_denied”}}

So the key appears to be accepted for model listing, and the model IDs are available, but inference requests are forbidden across models. This looks more like an account/workspace entitlement or billing validation issue than a config/model ID issue.

@ryux1 somebody help ;_;

@anshumanb help me please

Hi Storypalse,

Thanks for running that test — that narrows it down a lot.

Since GET /v1/models returns 200 with the same AI_GATEWAY_API_KEY, the base URL, bearer header format, and key recognition look basically correct. And since POST /v1/chat/completions returns the same 403 access_denied for both xai/grok-4.3 and openai/gpt-5.4, this does not look like a single model ID problem either.

At this point I’d treat it as a workspace/account-side AI Gateway access issue unless one final direct curl test shows otherwise. I’d make sure the failing request is from a local terminal, not through your app or proxy:

curl -i "https://ai-gateway.vercel.sh/v1/chat/completions" \
  -H "Authorization: Bearer $AI_GATEWAY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai/gpt-5.4",
    "messages": [{ "role": "user", "content": "test" }],
    "stream": false
  }'

If that direct request still returns:

{"error":{"message":"Forbidden.","type":"access_denied"}}

then I don’t think more app-side debugging will help much. I’d open or update the support case and include:

GET /v1/models: 200
POST /v1/chat/completions: 403 access_denied
Same AI Gateway API key used for both
Models confirmed present: xai/grok-4.3, openai/gpt-5.4
Direct curl request also fails
Response headers from the 403, with secrets removed

Do not post the API key publicly, but the redacted response headers may help Vercel correlate the request internally.

I ran the direct terminal test without going through our app/proxy.

GET /v1/models still succeeds:

GET_MODELS_STATUS 200
MODEL_COUNT 280
HAS_XAI_GROK_4_3 True
HAS_OPENAI_GPT_5_4 True

Then I tested chat completions directly with the same AI Gateway key:

POST https://ai-gateway.vercel.sh/v1/chat/completions
model: openai/gpt-5.4

Result:

POST_CHAT_STATUS 403
POST_CHAT_BODY
{"error":{"message":"Forbidden.","type":"access_denied"}}

Response headers from the 403, with no request secrets included:

Cache-Control: public, max-age=0, must-revalidate
Content-Type: application/json
Date: Mon, 15 Jun 2026 01:29:33 GMT
Server: Vercel
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
Transfer-Encoding: chunked
Vary: rsc, next-router-state-tree, next-router-prefetch, next-router-segment-prefetch
X-Matched-Path: /v1/chat/completions
X-Vercel-Cache: MISS
X-Vercel-Id: icn1::cle1::dxbwl-1781486973628-586e22d274b4

So the direct curl/terminal request also fails the same way: models listing works, the model IDs are present, but inference returns 403 access_denied.

Anyone..? help me out from this issue..

it’s been a week…

Hi Storypalse,

Thanks for confirming the direct terminal test. That rules out the app/proxy path pretty well.

Since /v1/models returns 200 with the same key, but /v1/chat/completions returns 403 access_denied even from a plain curl request, I don’t think changing SDKs or app code is likely to fix this. The request shape also matches the documented AI Gateway chat completions format.

The only user-side thing I’d still try is creating a brand-new AI Gateway API key in the same Vercel team/workspace and running the exact same direct curl once. If the new key also gives:

GET /v1/models => 200
POST /v1/chat/completions => 403 access_denied

then this looks like something Vercel needs to check for that workspace/key path.

I’d update the support case with this exact summary:

GET /v1/models: 200
POST /v1/chat/completions: 403 access_denied
Same AI Gateway API key used for both
Direct terminal request, no app/proxy
Models are listed as available
X-Vercel-Id: icn1::cle1::dxbwl-1781486973628-586e22d274b4
Date: Mon, 15 Jun 2026 01:29:33 GMT

Don’t post the API key publicly, but the X-Vercel-Id and timestamp are the most useful parts for Vercel to correlate internally.

Thanks, we followed that suggestion and tested again with a brand-new AI Gateway API key from the same workspace. No request secrets included here.

Direct terminal result with the new key:

GET /v1/models: 200
MODEL_COUNT: 280
HAS_XAI_GROK_4_3: true
HAS_OPENAI_GPT_5_4: true

POST /v1/chat/completions
model: openai/gpt-5.4
status: 403
body: {"error":{"message":"Forbidden.","type":"access_denied"}}

403 response identifiers:

Date: Mon, 22 Jun 2026 03:18:12 GMT
X-Vercel-Id: icn1::cle1::z92pj-1782098292599-2ab771b7a1e6
X-Matched-Path: /v1/chat/completions
X-Vercel-Cache: MISS

So the behavior is unchanged with a newly created key: model listing succeeds, the models are available, but inference returns 403 access_denied.

We also tried to create a Vercel Support Case from the Vercel Agent flow. The agent prepared the case, but the case form is blocked for this Hobby workspace with this message:

Visit our Community for further help or create a paid account for dedicated AI → AI Gateway support.

Because of that, we cannot submit the support case directly from the Hobby account. Could someone from Vercel check whether this workspace/key path has an AI Gateway entitlement, billing validation, or account-side access issue?

Hi Storypalse,

Thanks for testing with a brand-new key too. That pretty much rules out a malformed request, stale key, app/proxy issue, and single-key corruption.

At this point I would not keep rotating keys or changing the SDK. The useful evidence is now:

Same workspace
Old key: GET models 200, POST chat 403
New key: GET models 200, POST chat 403
Direct terminal request, no app/proxy
Model IDs are listed as available
403 type: access_denied
X-Vercel-Id: icn1::cle1::z92pj-1782098292599-2ab771b7a1e6
Date: Mon, 22 Jun 2026 03:18:12 GMT

That pattern really does look like the key is valid for Gateway metadata but the workspace is blocked from inference for some account-side reason.

Since the support form is not available on the Hobby workspace, I’d avoid posting any more private/account details here. The safest thing is to keep this thread focused on the redacted request identifiers and ask for a Vercel team member to check the Gateway entitlement/access state for that workspace.

One last non-sensitive thing you can check yourself: in the Vercel dashboard, open the AI Gateway section and see whether the failed POST requests appear in Gateway logs/usage at all. If they do not appear, that would further suggest the request is being denied before a normal model invocation is created.

yes,i need