Postman para explorar una API

Cómo organizar requests en Postman mientras exploras una API, cómo convertir esas requests en checks que corren en CI y qué papel tiene Postman frente a las herramientas que usa el agente.

ExploraciónAPI

Dónde encaja Postman en este repo

Postman es tu herramienta de exploración manual: guardas requests, las agrupas, les pones variables y les agregas asserts pequeños. El agente trabaja distinto. Para la pierna API de la exploración, el repo le da tres herramientas con un trabajo cada una, y Postman queda como fallback.

Paso Herramienta Para qué
Leer el contrato OpenAPI MCP (solo lectura) Descubrir endpoints y schemas de request y response.
Obtener un token bun run api:login Escribe el token en .auth/tokens.env, nunca en un MCP.
Ejecutar requests autenticadas curl La ejecución real, con el token del paso anterior.
Fallback Postman (MCP o la app) Cuando el camino principal no sirve para el caso.

Ese reparto es la fila [API_TOOL] de la tabla de resolución de herramientas en .agents/instructions/agent-tool-resolution.md. El detalle del camino principal está en OpenAPI. Esta página cubre Postman como lo usa una persona: la app para explorar y el CLI para correr colecciones en un pipeline.

Workspace, collection y folders

Un workspace agrupa colecciones y environments de un proyecto. Dentro, una collection guarda las requests, y los folders las ordenan por dominio o por orden de ejecución.

Workspace: Mi Proyecto API
  Collection: Mi Proyecto API
    Auth/
      Login
      Refresh Token
    Users/
      Get Users
      Update Profile
    Orders/
      List Orders
      Create Order
  1. Crea el workspace

    Workspaces > Create Workspace. Elige Personal o Team según quién va a usarlo.

  2. Crea la collection

    Collections > New collection. Un nombre por API, no por ticket.

  3. Agrega folders y requests

    Nombra cada request por lo que prueba: Create Order (happy path), Get Orders - filtro por fecha. Un nombre como test1 no le dice nada a quien abra la colección después.

Environments y variables

Un environment es un juego de variables por ambiente (local, staging, ...). Cambias de ambiente con un selector y las mismas requests apuntan a otro servidor.

Variable Valor de ejemplo Quién la llena
base_url https://api.example.com Tú, una vez por environment
api_url {{base_url}}/api Tú (se arma a partir de otra variable)
test_email qa@example.com Tú
test_password (el valor de tu .env) Tú, solo en tu máquina
access_token (vacío) El script del request de login
user_id (vacío) El script del request de login

Alcances de variables

Postman tiene tres alcances que usas desde los scripts:

// Environment: cambia con el ambiente seleccionado
pm.environment.set('key', 'value');
pm.environment.get('key');

// Collection: compartida por todas las requests de la colección
pm.collectionVariables.set('key', 'value');

// Global: compartida entre colecciones del workspace
pm.globals.set('key', 'value');

Variables dinámicas

Para datos de prueba que no deben repetirse, Postman genera valores en cada envío:

{
  "id": "{{$guid}}",
  "timestamp": "{{$timestamp}}",
  "random": "{{$randomInt}}",
  "email": "{{$randomEmail}}",
  "name": "{{$randomFullName}}"
}

Encadenar requests

Una request guarda un valor de su response y la siguiente lo usa en la URL o el body. En el script post-response de la request A:

const response = pm.response.json();
pm.environment.set('product_id', response.id);

Y la URL de la request B: {{api_url}}/products/{{product_id}}.

Autenticación

El patrón más simple: un request Login que guarda el token en el environment, y el resto de requests lo manda como Bearer.

POST {{base_url}}/auth/login con body raw JSON:

{
  "email": "{{test_email}}",
  "password": "{{test_password}}"
}

Script post-response del login:

pm.test('Login exitoso', function () {
  pm.response.to.have.status(200);
});

const response = pm.response.json();
pm.environment.set('access_token', response.access_token);
pm.environment.set('user_id', response.user.id);

En la pestaña Authorization de la collection elige Bearer Token con el valor {{access_token}}, y deja cada request en "Inherit auth from parent". Así no repites el header en cada request. Los nombres de campo (access_token, user.id) dependen de tu API: revísalos en el schema antes de copiar el script.

Credenciales

Las credenciales de prueba viven en .env. No las escribas en un environment que se sincroniza con un workspace de equipo ni en un JSON exportado que vaya a git. Exporta el environment con esos valores vacíos y que cada persona los complete en su máquina.

Scripts y tests

Cada request tiene dos scripts. El pre-request corre antes de enviar y sirve para preparar datos o avisar de un problema. El post-response corre al recibir la respuesta y ahí van los asserts con pm.test. En versiones anteriores de la app el post-response estaba en una pestaña llamada Tests.

Pre-request: avisar si el token venció

const token = pm.environment.get('access_token');

if (!token) {
  console.warn('No hay token. Ejecuta Login primero.');
} else {
  try {
    const payload = JSON.parse(atob(token.split('.')[1]));
    if (Date.now() > payload.exp * 1000) {
      console.warn('Token expirado. Ejecuta Refresh Token.');
    }
  } catch (e) {
    // El token no es un JWT: no hay fecha que revisar
  }
}

Post-response: status, estructura y valores

pm.test('Status 201 Created', function () {
  pm.response.to.have.status(201);
});

pm.test('Estructura correcta', function () {
  const r = pm.response.json();
  pm.expect(r).to.have.property('id');
  pm.expect(r.price).to.be.a('number');
  pm.expect(r.tags).to.be.an('array');
});

pm.test('Valores válidos', function () {
  const r = pm.response.json();
  pm.expect(r.price).to.be.above(0);
  pm.expect(r.status).to.be.oneOf(['active', 'pending', 'inactive']);
});

Validar contra un JSON Schema

const schema = {
  type: 'object',
  required: ['id', 'name', 'price'],
  properties: {
    id: { type: 'string' },
    name: { type: 'string' },
    price: { type: 'number' },
  },
};

pm.test('Schema válido', function () {
  pm.response.to.have.jsonSchema(schema);
});

Permisos

Dos casos que conviene tener en cualquier colección: la request sin token y la request a datos de otro usuario.

// Request sin header Authorization
pm.test('Rechaza sin token', function () {
  pm.response.to.have.status(401);
});

// Request con tu token pidiendo datos de otro usuario
pm.test('No expone datos de otro usuario', function () {
  if (pm.response.code === 403) return;
  pm.response.to.have.status(200);
  pm.expect(pm.response.json()).to.be.an('array').that.is.empty;
});

Que la API responda 403 o una lista vacía depende de su diseño. Confírmalo con el equipo antes de fijar el assert a uno de los dos.

Correr la colección entera

El Collection Runner de la app ejecuta todas las requests en orden. Abre el menú de la collection, elige Run, selecciona el environment y, si la API tiene rate limiting, agrega un delay entre requests (100 ms suele alcanzar).

El orden importa cuando las requests dependen unas de otras:

1. Auth/
     Login               -> guarda access_token
2. Setup/
     Get Products        -> guarda product_id
3. CRUD/
     Create Order        -> usa product_id, guarda new_order_id
     Get Order
     Update Order
     Delete Order        -> limpia lo que creó
4. Permisos/
     Access Other User Data

Postman en CI: Postman CLI y Newman

Para correr una colección en un pipeline hay dos runners. El Postman CLI es el oficial de Postman y el que recomendamos: se autentica con tu API key y puede correr una colección por ID o desde un archivo exportado. Newman es el runner open source de siempre; sirve si no quieres atar el pipeline a una cuenta de Postman.

Lo que trae el repo

El boilerplate no incluye colecciones ni un workflow de Postman. Los ejemplos de abajo son el patrón para cuando tu equipo decida versionar una colección.

Postman CLI

# Instalar (Linux / macOS)
curl -o- "https://dl-cli.pstmn.io/install/unix.sh" | sh

# Autenticarse con la API key
postman login --with-api-key "$POSTMAN_API_KEY"

# Correr una colección exportada con su environment
postman collection run postman/collection.json -e postman/staging.environment.json

# O por ID de colección, con reportes JUnit y HTML
postman collection run <collection-id> -e <environment-id> \
  -r cli,junit,html \
  --reporter-junit-export reports/postman-junit.xml \
  --reporter-html-export reports/postman.html

En GitHub Actions, la API key va como secret del repositorio:

name: API Tests (Postman)

on: [pull_request]

jobs:
  postman:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Install Postman CLI
        run: curl -o- "https://dl-cli.pstmn.io/install/unix.sh" | sh

      - name: Login
        run: postman login --with-api-key ${{ secrets.POSTMAN_API_KEY }}

      - name: Run collection
        run: postman collection run postman/collection.json -e postman/staging.environment.json

Newman

npm install -g newman

newman run postman/collection.json \
  -e postman/staging.environment.json \
  -r cli,junit \
  --reporter-junit-export reports/newman-junit.xml

Newman no necesita cuenta. El reporter HTML no viene incluido: se instala aparte (newman-reporter-html) y se activa con -r cli,html.

El Postman MCP, a nivel del harness

Postman publica un server MCP remoto, https://mcp.postman.com/mcp, que se autentica con tu cuenta de Postman. El repo no lo declara en .mcp.json ni en sus equivalentes: un server remoto cuyo único contenido del lado del proyecto sería una clave es asunto del harness, no del repo (la lista de esos servers vive en cli/lib/harness-level-mcps.ts). Lo conectas una vez por máquina y el agente lo resuelve por capacidad, sea cual sea el prefijo con el que aparezcan sus herramientas.

Cómo conectarlo
Claude Code: un server de usuario (claude mcp add --scope user) o un conector desde claude.ai. OpenCode: la config global ~/.config/opencode/opencode.json. Codex: codex mcp add postman --url https://mcp.postman.com/mcp y después codex mcp login postman (OAuth: el token queda en el almacén de Codex y sirve igual para la CLI y la app de escritorio). Tu API key de Postman, la de postman login, es tuya y no va en el .env del proyecto. Detalle por harness en Variables de entorno.
Rol
Fallback de [API_TOOL]. El agente lo usa cuando la ruta principal (OpenAPI MCP para el schema, curl para ejecutar) no cubre el caso, por ejemplo para consultar o correr una colección que el equipo ya mantiene en Postman.
Si falla
Una key vacía no detiene el arranque del agente: el error aparece recién en la primera llamada, como un 401. Revisa la credencial donde la conectaste (el harness, no .env) y reinicia la sesión del agente, porque las variables se leen al arrancar el MCP. bun run setup:doctor te dice si tu config de usuario declara el server; un conector de claude.ai no deja archivo y lo reporta como no detectable.

Buenas prácticas