n4nAI

Testing the OpenAI API in Postman: a starter collection

A hands-on tutorial for building a Postman collection to test the OpenAI API, with runnable requests, env vars, and example responses step by step.

n4n Team2 min read506 words

Audio narration

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

Testing LLM endpoints by hand saves hours before you wire them into app code. This tutorial builds a postman collection openai api starter that covers auth, chat completions, and model listing with environment variables and test scripts. You’ll end with a runnable collection you can export, share, or drive from CI.

Prerequisites

  • Postman v10+ (or Newman for headless runs)
  • A valid OpenAI API key (any OpenAI-compatible key works)
  • Bash terminal for the CLI section
  • jq optional, for piping curl output

If you only have a gateway key, the requests below still apply as long as the endpoint speaks the OpenAI shape.

Environment setup

Never hardcode secrets in a collection JSON. Create a Postman environment named openai-env with two values:

{
  "name": "openai-env",
  "values": [
    { "key": "base_url", "value": "https://api.openai.com", "type": "default" },
    { "key": "api_key", "value": "sk-your-key", "type": "secret" }
  ]
}

Reference them later as {{base_url}} and {{api_key}}. The secret type prevents the value from rendering in shared exports.

Build the postman collection openai api skeleton

Start with a minimal v2.1.0 collection. The structure below defines two folders and one request each. You can paste this directly into a .json file and import it.

{
  "info": {
    "name": "OpenAI API Starter",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "item": [
    {
      "name": "Models",
      "item": [
        {
          "name": "List models",
          "request": {
            "method": "GET",
            "header": [ { "key": "Authorization", "value": "Bearer {{api_key}}" } ],
            "url": { "raw": "{{base_url}}/v1/models", "host": ["{{base_url}}"], "path": ["v1","models"] }
          }
        }
      ]
    },
    {
      "name": "Chat",
      "item": [
        {
          "name": "Create completion",
          "request": {
            "method": "POST",
            "header": [
              { "key": "Authorization", "value": "Bearer {{api_key}}" },
              { "key": "Content-Type", "value": "application/json" }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"model\": \"gpt-4o-mini\",\n  \"messages\": [ { \"role\": \"user\", \"content\": \"Say hello in JSON.\" } ],\n  \"temperature\": 0.2\n}"
            },
            "url": { "raw": "{{base_url}}/v1/chat/completions", "host": ["{{base_url}}"], "path": ["v1","chat","completions"] }
          }
        }
      ]
    }
  ]
}

That is the backbone. Now we tighten each request with tests and variables.

List models request

The GET /v1/models call verifies connectivity and key scope. In Postman’s Tests tab for that request, add:

pm.test("status 200", () => pm.response.to.have.status(200));
pm.test("returns list", () => {
  const body = pm.response.json();
  pm.expect(body.object).to.equal("list");
  pm.expect(body.data).to.be.an("array");
});

Equivalent curl for a quick local check:

curl {{base_url}}/v1/models \
  -H "Authorization: Bearer $API_KEY" | jq '.object'

Expected output from the API:

{
  "object": "list",
  "data": [
    { "id": "gpt-4o", "object": "model", "owned_by": "openai" },
    { "id": "gpt-4o-mini", "object": "model", "owned_by": "openai" }
  ]
}

Chat completion request

The POST /v1/chat/completions request is where most integration bugs hide. Use a fixed low temperature for reproducible tests. In the Tests tab:

pm.test("status 200", () => pm.response.to.have.status(200));
pm.test("has assistant message", () => {
  const body = pm.response.json();
  pm.expect(body.choices).to.be.an("array").with.length.of.at.least(1);
  pm.expect(body.choices[0].message.content).to.be.a("string");
  pm.expect(body.usage.total_tokens).to.be.a("number");
});

Expected response shape:

{
  "id": "chatcmpl-123",
  "object": "chat.completion",
  "choices": [
    {
      "index": 0,
      "message": { "role": "assistant", "content": "{\"greeting\":\"hello\"}" },
      "finish_reason": "stop"
    }
  ],
  "usage": { "prompt_tokens": 10, "completion_tokens": 5, "total_tokens": 15 }
}

Parameterize model and prompt

Hardcoding gpt-4o-mini in the body forces you to edit raw JSON to test another model. Add collection variables model and prompt, then rewrite the body as:

{
  "model": "{{model}}",
  "messages": [ { "role": "user", "content": "{{prompt}}" } ],
  "temperature": 0.2
}

Set defaults in the collection’s Variables tab:

{ "model": "gpt-4o-mini", "prompt": "Say hello in JSON." }

Now a runner can override them per iteration without touching the request.

Full collection with tests

Here is the completed importable collection. It includes the test scripts inline.

{
  "info": {
    "name": "OpenAI API Starter",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "variable": [
    { "key": "model", "value": "gpt-4o-mini" },
    { "key": "prompt", "value": "Say hello in JSON." }
  ],
  "item": [
    {
      "name": "Models",
      "item": [
        {
          "name": "List models",
          "request": {
            "method": "GET",
            "header": [ { "key": "Authorization", "value": "Bearer {{api_key}}" } ],
            "url": { "raw": "{{base_url}}/v1/models", "host": ["{{base_url}}"], "path": ["v1","models"] }
          },
          "event": [
            { "listen": "test", "script": { "exec": [
              "pm.test('status 200', () => pm.response.to.have.status(200));",
              "const b = pm.response.json();",
              "pm.expect(b.object).to.equal('list');"
            ] } }
          ]
        }
      ]
    },
    {
      "name": "Chat",
      "item": [
        {
          "name": "Create completion",
          "request": {
            "method": "POST",
            "header": [
              { "key": "Authorization", "value": "Bearer {{api_key}}" },
              { "key": "Content-Type", "value": "application/json" }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"model\": \"{{model}}\",\n  \"messages\": [ { \"role\": \"user\", \"content\": \"{{prompt}}\" } ],\n  \"temperature\": 0.2\n}"
            },
            "url": { "raw": "{{base_url}}/v1/chat/completions", "host": ["{{base_url}}"], "path": ["v1","chat","completions"] }
          },
          "event": [
            { "listen": "test", "script": { "exec": [
              "pm.test('status 200', () => pm.response.to.have.status(200));",
              "const b = pm.response.json();",
              "pm.expect(b.choices[0].message.content).to.be.a('string');",
              "pm.expect(b.usage.total_tokens).to.be.a('number');"
            ] } }
          ]
        }
      ]
    }
  ]
}

Run from CLI with Newman

Postman GUI is fine for exploration, but CI needs headless execution. Export the collection and environment, then:

npm install -g newman
newman run openai-starter.json -e openai-env.json --reporters cli

Newman prints per-request pass/fail. If a model is deprecated, the chat test fails fast instead of silently returning garbage in your app.

If you point the same base_url at an OpenAI-compatible gateway such as n4n.ai, the postman collection openai api requests exercise 240+ models behind one endpoint without changing auth shape or test logic. That’s useful when you want fallback coverage during provider incidents.

Error-path testing

A starter collection is incomplete without the negative case. Duplicate the chat request, name it Create completion bad key, and override api_key in a local environment with sk-invalid. Expect:

{
  "error": { "message": "Incorrect API key provided", "type": "invalid_request_error", "code": "invalid_api_key" }
}

Add a test that asserts status 401:

pm.test("401 on bad key", () => pm.response.to.have.status(401));

This catches env misconfiguration before a deploy.

Python sanity check

Sometimes you need to confirm Postman isn’t masking a transport issue. A minimal Python equivalent:

import os, requests

r = requests.get(
    "https://api.openai.com/v1/models",
    headers={"Authorization": f"Bearer {os.environ['API_KEY']}"}
)
print(r.status_code, r.json()["object"])

If this prints 200 list but Postman fails, the problem is environment or proxy, not the API.

Checkpoint summary

Request Expected status Key assertion
List models 200 object == "list"
Chat completion 200 choices[0].message.content is string
Chat bad key 401 error type invalid_request_error

Keep the collection in version control. Treat the postman collection openai api file as executable documentation—when the contract drifts, the tests tell you first.

Tagspostmanopenai-apitestingcollection

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 →