Una misma herramienta puede parecer idéntica en la terminal y, sin embargo, estar consumiendo dos sistemas de facturación distintos.

Ese detalle importa mucho con Codex CLI.

Si ejecutamos:

codex exec "revisa este repositorio"

la pregunta relevante no es sólo qué modelo utiliza. También hay que preguntar:

¿Codex está autenticado con una cuenta de ChatGPT o con una API key?

La diferencia determina de dónde sale el uso.

Según la documentación actual de OpenAI, iniciar sesión en Codex con ChatGPT usa la asignación y facturación del plan de ChatGPT, mientras que usar una API key utiliza la facturación estándar de la API.

Pero la diferencia no es sólo económica. El login con ChatGPT aplica permisos, RBAC y políticas del workspace de ChatGPT; una API key sigue las políticas de la organización/proyecto de API. Además, Codex Cloud requiere login con ChatGPT y algunas funciones que dependen del workspace de ChatGPT o de servicios cloud pueden estar limitadas o no disponibles con API-key auth.

Eso permite un patrón muy útil para automatizaciones, servidores y bots: mantener la experiencia interactiva normal de Codex con ChatGPT, pero ejecutar ciertos jobs locales con una API key cuando queremos que se cobren contra el saldo de la plataforma API.

Este artículo explica cómo hacerlo sin incluir nombres reales de hosts, organizaciones, proyectos, IDs, rutas privadas ni credenciales. Todos los ejemplos usan valores ficticios o placeholders.

Primero: hay dos tipos de “créditos” que no debemos confundir

OpenAI ofrece hoy créditos en más de un contexto.

Créditos de ChatGPT / Codex

Pueden aparecer en la configuración de uso de ChatGPT o Codex y sirven para extender ciertas funciones después de agotar el uso incluido en un plan compatible.

OpenAI aclara expresamente que estos créditos no son créditos de la API.

Créditos de la plataforma API

Aparecen en la sección de billing de platform.openai.com.

Conceptualmente:

API billing
  └── prepaid / granted API credit
            ↓
      OpenAI API requests
            ↓
       API key auth

Si el saldo está en el dashboard de API Billing, la forma de consumirlo desde Codex es hacer que Codex ejecute usando autenticación por API key.

Ésta es la distinción más importante de toda la guía.

Caso 1: usar la API key sólo para un codex exec

Para un job aislado, no hace falta cambiar permanentemente la sesión normal de Codex.

Podemos suministrar una credencial únicamente al proceso que ejecuta el comando:

CODEX_API_KEY="$MY_OPENAI_KEY" \
  codex exec "resume el estado del repositorio sin ejecutar scripts del proyecto"

La idea es:

shell
  │
  ├─ sesión normal de Codex → puede seguir autenticada con ChatGPT
  │
  └─ este proceso concreto
         │
         └─ CODEX_API_KEY
                ↓
             API billing

OpenAI documenta este patrón para automatizaciones no interactivas: CODEX_API_KEY puede aplicarse sólo a la invocación de codex exec que la necesita.

Pero hay una frontera de seguridad esencial:

Usa este patrón sólo cuando el código y los comandos que Codex pueda ejecutar sean confiables.

Los procesos hijos pueden heredar variables de entorno. Si codex exec termina ejecutando tests, scripts de build, hooks, lifecycle scripts o cualquier código controlado por un repositorio no confiable, ese código podría intentar leer y exfiltrar CODEX_API_KEY.

Por eso “variable sólo para codex exec” no significa automáticamente “secreto invisible para todo lo que Codex ejecute”.

No escribas la key literalmente en el historial

Aunque esto funciona técnicamente:

CODEX_API_KEY='sk-proj-REAL-SECRET-HERE' codex exec "..."

no es una buena forma de operar manualmente en un servidor.

La clave puede terminar en:

  • historial del shell;
  • logs de troubleshooting;
  • capturas de pantalla;
  • documentación pegada en issues;
  • output de debugging;
  • scripts versionados accidentalmente.

Una forma más segura para una sesión interactiva es leerla sin eco:

read -rsp "OpenAI API key: " CODEX_API_KEY
echo
export CODEX_API_KEY

# Sólo para una tarea que no ejecute código no confiable.
codex exec "inspecciona el repositorio"

unset CODEX_API_KEY

Esto evita que la key aparezca directamente en la línea escrita en el historial, pero no aísla la variable de procesos hijos. Si la tarea puede ejecutar código no confiable, hay que usar aislamiento adicional.

Caso 2: autenticar Codex una vez con codex login --with-api-key

Codex también permite guardar autenticación por API key.

El comando recibe la clave por stdin:

printenv OPENAI_API_KEY | codex login --with-api-key

Si nuestra variable se llama CODEX_API_KEY, el mismo patrón es:

printenv CODEX_API_KEY | codex login --with-api-key

Después podemos verificar el estado:

codex login status

y ejecutar normalmente:

codex exec "analiza el proyecto"

La diferencia respecto al método anterior es importante.

Variable temporal

CODEX_API_KEY="$MY_OPENAI_KEY" codex exec "..."

La credencial existe en el entorno de ese proceso y puede ser heredada por procesos hijos.

Login persistente

printenv CODEX_API_KEY | codex login --with-api-key

La variable puede desaparecer inmediatamente después, pero Codex conserva credenciales de autenticación cacheadas para ejecuciones futuras bajo ese usuario.

En otras palabras:

variable temporal
      ↓
codex login --with-api-key
      ↓
credencial/token guardado por Codex
      ↓
futuros codex exec

Decir que “la variable sólo existió durante el login” no significa que la autenticación también sea temporal.

¿Podemos hacer que la variable exista sólo durante el comando de login?

Sí.

Por ejemplo:

CODEX_API_KEY="$MY_OPENAI_KEY" \
  sh -c 'printf "%s\n" "$CODEX_API_KEY" | codex login --with-api-key'

Cuando termina ese sh, la variable deja de existir en el proceso padre.

Pero Codex ya habrá guardado la autenticación.

Éste es un detalle muy útil para provisionar servidores:

secret inyectado
     ↓
un solo comando de provisioning
     ↓
codex login --with-api-key
     ↓
secret retirado del entorno
     ↓
credencial de Codex sigue cacheada

El login persistente también es un secreto

Eliminar OPENAI_API_KEY o CODEX_API_KEY del entorno no elimina las credenciales que Codex haya cacheado.

La documentación oficial indica que Codex puede guardar credenciales:

  • en ~/.codex/auth.json;
  • o en el credential store/keyring del sistema operativo.

El almacenamiento puede controlarse en config.toml:

# file | keyring | auto | ephemeral
cli_auth_credentials_store = "keyring"

Para un bot estable, keyring es preferible cuando el sistema operativo ofrece un credential store fiable. Si se usa file, hay que tratar ~/.codex/auth.json como una contraseña: no versionarlo, no copiarlo a tickets o chats y restringir cuidadosamente sus permisos.

También hay una consecuencia importante para aislamiento: código que corre bajo el mismo usuario del sistema puede intentar acceder a las credenciales que ese usuario puede leer. Por eso el login persistente debe considerarse una característica de un entorno confiable, no una forma de hacer segura la ejecución de código arbitrario.

Si la tarea implica repositorios, PRs o scripts no confiables, usa separación de procesos/usuarios o un mecanismo de CI diseñado para que el secreto no quede disponible al código del repositorio.

Un patrón manual razonable

Para no escribir la key en la línea de comandos:

read -rsp "OpenAI API key: " CODEX_API_KEY
echo
printf '%s\n' "$CODEX_API_KEY" | codex login --with-api-key
unset CODEX_API_KEY

Luego:

codex login status

Esto combina tres ideas útiles:

  1. la key no se muestra mientras se escribe;
  2. no aparece como argumento literal del comando;
  3. se elimina de la variable del shell después de autenticar.

Pero el login resultante sigue siendo sensible y debe almacenarse en un entorno confiable.

Bots en Linux: importa qué usuario ejecuta Codex

Supongamos un servidor Linux genérico donde un bot ejecuta periódicamente:

codex exec "revisa el estado del repositorio"

Si autenticamos Codex manualmente bajo un usuario y luego el servicio corre bajo otro, el bot puede no ver esa autenticación.

El principio es:

Haz el login bajo la misma identidad de sistema que ejecutará codex exec, pero dedica esa identidad a tareas confiables.

Por ejemplo, si un servicio usa:

[Service]
User=automation

la autenticación debe quedar accesible para automation, no solamente para otro usuario con sesión SSH.

Al mismo tiempo, no conviene ejecutar bajo ese mismo usuario scripts arbitrarios procedentes de repositorios no confiables.

systemd: inyectar la key sólo en un servicio dedicado y confiable

Otra opción es proporcionar la key al proceso del servicio mediante un archivo de entorno restringido:

sudo install -m 600 /dev/null /etc/example-bot.env

Contenido conceptual:

CODEX_API_KEY=sk-proj-REDACTED

Y en un override de systemd:

[Service]
User=automation
EnvironmentFile=/etc/example-bot.env
NoNewPrivileges=true

Después:

sudo systemctl daemon-reload
sudo systemctl restart example-bot.service

Este patrón sólo es apropiado si el servicio es dedicado y todo el código que ejecutará con esa variable presente es confiable. EnvironmentFile no crea una bóveda alrededor del secreto: la variable forma parte del entorno del servicio y puede heredarse por sus procesos descendientes.

Por tanto:

servicio dedicado + código confiable    → razonable
servicio que ejecuta PRs/scripts ajenos → NO entregar la key de esta forma

Si el bot procesa código potencialmente hostil, separa el componente que posee la credencial del componente que ejecuta el código, o usa un mecanismo de proxy/aislamiento equivalente.

¿Cuál enfoque conviene para un bot?

Hay dos estrategias razonables para entornos confiables.

A. Login persistente de Codex

Provisionamos una vez:

read -rsp "OpenAI API key: " OPENAI_API_KEY
echo
printf '%s\n' "$OPENAI_API_KEY" | codex login --with-api-key
unset OPENAI_API_KEY

Luego el bot ejecuta:

codex exec "..."

Ventaja: la API key original no necesita permanecer como variable de entorno de cada ejecución.

Riesgo: Codex mantiene credenciales cacheadas. Usa keyring cuando sea posible y protege el usuario del servicio como una identidad privilegiada.

B. Credencial inyectada por ejecución

El secret manager o la infraestructura entrega:

CODEX_API_KEY

sólo a la invocación que la necesita:

CODEX_API_KEY="$MY_OPENAI_KEY" codex exec "..."

Ventaja: la autenticación queda controlada externamente y puede rotarse sin rehacer un login manual.

Riesgo: los descendientes de ese proceso pueden heredar la variable. No mezcles este patrón con código no confiable.

GitHub Actions: no uses la API key como variable de todo el job

En CI, guardar la key en el secret store es necesario, pero no suficiente.

Este patrón es peligroso cuando el job hace checkout y ejecuta código del repositorio:

# Evitar en jobs que ejecutan código controlado por el repositorio.
env:
  CODEX_API_KEY: ${{ secrets.OPENAI_API_KEY }}

Tests, builds, hooks, scripts de dependencias o una action comprometida podrían leerla.

Para GitHub Actions, la documentación actual de OpenAI recomienda openai/codex-action@v1, que instala Codex y levanta un proxy para reducir la exposición directa de la API key:

- uses: actions/checkout@v5
  with:
    persist-credentials: false

- name: Run Codex
  uses: openai/codex-action@v1
  with:
    openai-api-key: ${{ secrets.OPENAI_API_KEY }}
    prompt: |
      Revisa el cambio y propone el ajuste mínimo necesario.

La idea importante es que los pasos de setup y el código del repositorio no reciban la key como una variable de entorno general del job.

Para CI fuera de GitHub Actions, el principio es el mismo: entrega CODEX_API_KEY sólo al componente que llama a Codex y asegúrate de que no haya código no confiable en el mismo entorno de proceso.

API key y código no confiable: una frontera crítica

Hay que separar dos mundos:

componente con el secreto
        │
        │ llamada a OpenAI
        ▼
      Codex

código no confiable
        │
        └── NO debería poder leer el secreto

Esto es especialmente importante en:

  • pull requests de forks;
  • repositorios públicos;
  • scripts de terceros;
  • runners self-hosted compartidos;
  • tareas donde Codex ejecuta tests o tooling del repositorio.

La autenticación resuelve quién paga la llamada. No resuelve automáticamente quién puede leer la credencial.

Cómo verificar qué estamos usando

Antes de automatizar, conviene comprobar el estado:

codex login status

OpenAI también permite limpiar las credenciales almacenadas con:

codex logout

No asumas que la sesión interactiva y el job automatizado necesariamente usan el mismo método de autenticación.

Qué pasa cuando se agota el saldo API

La plataforma API admite billing prepago y auto-recharge configurable.

Si el saldo disponible llega al límite y no existe capacidad adicional de facturación, las requests API pueden dejar de procesarse hasta que haya saldo o capacidad de pago disponible.

Esto es independiente de la asignación incluida en un plan de ChatGPT.

Por eso conviene distinguir operacionalmente:

ChatGPT / Codex usage
        ≠
API platform usage

Un bot que funciona con API key puede quedarse sin presupuesto aunque la cuenta siga pudiendo usar Codex mediante ChatGPT, y viceversa.

Checklist para una automatización segura

Antes de poner codex exec en un bot o servicio:

  • identifica si quieres facturación de ChatGPT o de API;
  • recuerda que API-key auth no ofrece exactamente las mismas capacidades que ChatGPT login;
  • si necesitas Codex Cloud, usa login con ChatGPT;
  • si quieres API billing para automatización local, usa autenticación por API key;
  • no pegues la key literal en scripts versionados;
  • no la incluyas en issues, logs ni screenshots;
  • evita poner secretos como argumentos visibles;
  • no expongas CODEX_API_KEY como variable general de jobs que ejecutan código del repositorio;
  • en GitHub Actions, prefiere openai/codex-action@v1;
  • para login persistente, considera cli_auth_credentials_store = "keyring";
  • trata ~/.codex/auth.json como una contraseña si se usa almacenamiento por archivo;
  • recuerda que un login guardado persiste aunque la variable desaparezca;
  • dedica el usuario del servicio a tareas confiables;
  • separa la credencial de cualquier código no confiable que Codex vaya a ejecutar;
  • revisa el billing de API independientemente del uso de ChatGPT.

La idea principal

La pregunta “¿cómo uso mi saldo API desde codex exec?” se reduce primero a una cuestión de ruta de autenticación:

Codex + ChatGPT login
        ↓
ChatGPT usage / billing
        +
workspace / cloud capabilities

Codex + API key
        ↓
API usage / billing
        +
local / programmatic workflows

Pero después aparece una segunda pregunta igual de importante:

¿Qué código puede ver la credencial mientras Codex trabaja?

Para una ejecución aislada y confiable, podemos inyectar CODEX_API_KEY sólo en ese proceso.

Para un bot estable y confiable, podemos autenticar Codex una vez con codex login --with-api-key y proteger el credential store, o hacer que la infraestructura entregue la variable sólo a la invocación necesaria.

Para código no confiable, ninguna de esas dos técnicas por sí sola constituye aislamiento: hay que separar el secreto del entorno que ejecuta ese código.

El punto más importante no es memorizar un comando. Es diseñar claramente quién posee la credencial, cuánto tiempo vive, dónde queda cacheada, qué proceso puede verla y contra qué sistema de facturación queremos ejecutar.

Fuentes