n4nAI

Setting up environment variables for LLM API keys in Postman

Step-by-step guide to setting up Postman environment variables for LLM API keys, enabling secure testing of OpenAI-compatible inference APIs.

n4n Team4 min read933 words

Audio narration

Coming soon — every post will get a voice note here.

Hardcoding LLM credentials in Postman requests is a fast way to leak them into shared workspaces or exported collections. Setting up Postman environment variables for API keys lets you keep tokens in a scoped, switchable context and reference them as {{api_key}} across every call. This guide walks through a reproducible setup for testing OpenAI-compatible inference endpoints without touching the secret in your request definitions.

Why inline keys break

When you paste a bearer token directly into the Authorization tab, it gets saved in the collection JSON. Export that collection for a teammate or commit it to a repo and the key is gone. Postman environments solve this by storing values separately from requests. The request stays portable; the secret stays local or in a vault.

Another failure mode: you test against OpenAI, then need to hit a self-hosted vLLM server, then a gateway. If the host and key are baked into 40 saved requests, you now have 40 edits. Externalizing those into Postman environment variables for API keys and base URLs collapses that to one switch.

Step 1: Create a dedicated environment

Open Postman. Click the gear icon (Manage Environments) at the top right, then Add. Name it something explicit like LLM-Dev-OpenAI. Do not reuse the global scope for secrets—globals apply everywhere and are easy to accidentally export.

After creating it, select the environment from the dropdown next to the gear so it is active. Any {{variable}} reference in a request now resolves against this context.

Step 2: Define the core variables

At minimum, define three variables: base_url, api_key, and model. The base_url points at the API root. The api_key is your bearer token. Mark it as secret type so Postman masks it in the UI and excludes it from regular exports.

A minimal environment export looks like this:

{
  "name": "LLM-Dev-OpenAI",
  "values": [
    { "key": "base_url", "value": "https://api.openai.com/v1", "enabled": true },
    { "key": "api_key", "value": "sk-your-actual-key-here", "enabled": true, "type": "secret" },
    { "key": "model", "value": "gpt-4o-mini", "enabled": true }
  ]
}

You can add org_id or project if your provider requires them. Keep variable names lowercase with underscores—they are easiest to reference in scripts.

Step 3: Wire variables into the request

Create a new request. Set the method to POST and the URL to:

{{base_url}}/chat/completions

In the Authorization tab, pick Bearer Token and put {{api_key}} in the token field. Postman resolves the variable before sending; the actual token never appears in the request builder if the environment is not selected.

If the API expects the key in a header instead, go to Headers and add:

Key Value
Authorization Bearer {{api_key}}

Using {{base_url}} in the path means you can later point the same request at https://localhost:8000/v1 by swapping environments.

Step 4: Use a pre-request script for dynamic headers

Some gateways and providers honor cache-control or routing hints. Rather than hand-editing headers per call, set them in a pre-request script. This runs before every request in the collection if you attach it at the collection level.

// Postman pre-request script (collection-level)
pm.environment.set("trace_id", pm.variables.replaceIn("{{$guid}}"));
pm.request.headers.upsert({
  key: "X-Trace-Id",
  value: pm.environment.get("trace_id")
});
// Forward a provider cache hint if your gateway supports it
pm.request.headers.upsert({
  key: "Cache-Control",
  value: "max-age=300"
});

This keeps cross-cutting concerns out of individual requests. If you later migrate to a gateway that honors client routing directives, you extend the script once.

Step 5: Switch contexts without editing requests

Duplicate the environment (gear → Duplicate) and rename to LLM-Prod or LLM-Local. Change only base_url and api_key. The model variable can stay or be overridden per environment.

If you route through n4n.ai, its OpenAI-compatible endpoint fronts 240+ models and applies fallback when a provider is degraded, so you set base_url to that single endpoint and only vary model. The same collection works unchanged.

To verify the active environment, check the top-right dropdown. A common bug: you edited LLM-Dev but LLM-Prod is selected, so nothing changes. Postman shows the active env name there—trust it.

Step 6: Send a minimal chat completion

With the environment selected, build a small body to confirm auth and routing:

{
  "model": "{{model}}",
  "messages": [
    { "role": "user", "content": "Return the JSON object {\"ok\":true}." }
  ],
  "max_tokens": 32,
  "temperature": 0
}

Hit Send. The request should resolve to https://api.openai.com/v1/chat/completions with Authorization: Bearer sk-.... If you used a gateway, the same body hits its endpoint and returns compatible output.

Step 7: Verify success and inspect resolution

A successful call returns HTTP 200 and a body shaped like:

{
  "id": "chatcmpl-...",
  "object": "chat.completion",
  "choices": [
    { "message": { "role": "assistant", "content": "{\"ok\":true}" } }
  ],
  "usage": { "prompt_tokens": 12, "completion_tokens": 5, "total_tokens": 17 }
}

To confirm variables actually substituted, open the Postman Console (View → Show Postman Console) and inspect the sent request. The resolved URL and headers should show real values, not {{}} placeholders. If you see literal {{api_key}} in the console, the environment is not active or the variable name is misspelled.

A quick local check outside Postman can catch key format issues:

import os
key = os.environ.get("LLM_API_KEY", "")
assert key.startswith("sk-") and len(key) > 20, "key looks malformed"
print("key length:", len(key))

This is optional but useful in CI where you reuse the same secret from env vars.

Security hygiene

Treat Postman environments like .env files. Never commit the exported *.postman_environment.json with a plaintext secret. Postman’s secret type prevents the value from appearing in standard exports, but it still lives in your local app data—rotate keys if the machine is compromised.

For team sharing, use the Postman Vault or your org’s secret manager. Inject the value at runtime via the Postman CLI (newman) with --env-var "api_key=$TOKEN" rather than baking it in.

Avoid printing pm.environment.get("api_key") to the console in scripts. The console is captured in bug reports.

Troubleshooting

401 Unauthorized – Environment not active, or api_key missing the sk- prefix. Hover the variable in the UI to see resolved value.

404 on /chat/completionsbase_url includes a trailing slash or missing /v1. Set it exactly to the API root without path.

CORS errors – Postman ignores CORS; if you see them, you are likely using the browserized version with a proxy misconfig. Use the desktop app.

Model not foundmodel variable mismatches provider catalog. For a gateway covering many models, the name must match exactly what the route expects.

Closing notes on scale

Once this pattern is in place, you can drive load tests, contract tests, and multi-provider comparisons from one collection. The request definitions never change; only the environment does. That is the whole point of Postman environment variables for API keys: the secret and the target are configuration, not code.

Tagspostmanapi-keysenvironment-variablestesting

Written by

n4n Team

The team building n4n — a single OpenAI-compatible API in front of 240+ models, with automatic fallback, load balancing and pay-per-token metering.

More from n4n Team →

All postman & insomnia llm api testing posts →