Cómo uso mi suscripción de Claude como API gratis — el proxy OAuth que lo cambia todo
Tengo una suscripción a Claude Max. Pago por ella. La uso todo el día con Claude Code en el terminal. Pero cuando quiero que mi agente de IA (Hermes) use Claude Sonnet para responderme por Telegram... necesito una API key que cuesta aparte. ¿Por qué no puedo reutilizar lo que ya pago?
Hoy lo resolvimos. Y el resultado es un proxy de 80 líneas en Node.js que cambia las reglas del juego.
El problema
La suscripción de Claude (Pro, Max) te da acceso a los modelos a través de la web y de Claude Code CLI. Pero si quieres usar la API de Anthropic desde tu propio código — un bot de Telegram, un agente, una app — necesitas una API key con billing separado. Tokens de entrada, tokens de salida, todo facturado aparte.
Yo tengo un agente llamado Harvie corriendo en mi VPS. Es un asistente personal que me habla por Telegram, gestiona mis datos de entrenamiento, me prepara el briefing diario y ejecuta herramientas. Hasta ahora usaba un modelo gratuito (StepFun vía OpenRouter), pero quería darle la potencia de Claude Sonnet. El problema: no quería pagar dos veces.
El descubrimiento
Cuando te logueas con Claude Code CLI (claude), se genera un token OAuth que se guarda en ~/.claude/.credentials.json. Ese token es el que autentica todas tus peticiones con tu suscripción. La pregunta era: ¿puedo usar ese mismo token para hacer llamadas a la API desde fuera de Claude Code?
La respuesta: sí, con dos trucos clave.
Los dos trucos que hacen que funcione
1. Authorization: Bearer (no x-api-key)
Las API keys normales de Anthropic usan el header x-api-key. Pero los tokens OAuth usan Authorization: Bearer <token>. Son mecanismos de autenticación diferentes. Si mandas un token OAuth como x-api-key, no funciona.
2. El header secreto: anthropic-beta
La API de Anthropic rechaza tokens OAuth a menos que incluyas un header específico:
anthropic-beta: oauth-2025-04-20
Sin este header, la API te devuelve un error. Con él, acepta tu token OAuth y responde como si fuera una API key normal. Tu suscripción Max cubre el coste.
La solución: un proxy local
En vez de modificar cada aplicación que quiera usar la API, montamos un proxy intermedio:
Hermes / curl / tu app
↓
Proxy local (:[IP]) ← inyecta token OAuth + headers
↓
api.anthropic.com ← responde con tu suscripción
El proxy es un servidor Node.js que:
- Escucha en
http://127.0.0.1:[IP] - Lee el token OAuth de Caude en cada petición
- Reemplaza la autenticación con
Bearer <token> - Añade el header
- Reenvía a
api.anthropic.comy streamea la respuesta de vuelta
Desde la perspectiva de Hermes (o cualquier otra app), es como hablar con la API de Anthropic directamente. No sabe que hay un proxy en medio.
El bug invisible que nos costó horas
La primera versión del proxy parecía funcionar. El test con curl devolvía respuestas perfectas. Pero Hermes fallaba con "Connection error" después de cada petición — aunque el proxy logueaba un HTTP 200 exitoso.
¿El problema? gzip.
fetch() de Node.js descomprime automáticamente las respuestas gzip. Pero no elimina el header content-encoding: gzip de la respuesta. Así que el proxy reenviaba datos ya descomprimidos con un header que decía "esto está comprimido". El SDK de Python de Anthropic (que usa Hermes/openclaw) intentaba descomprimir datos en texto plano y explotaba silenciosamente.
La solución es quirúrgica: tres delete en los headers.
// En los headers del REQUEST (no pedir gzip al upstream)
delete headers["accept-encoding"];
// En los headers del RESPONSE (no mentir al cliente)
delete resHeaders["content-encoding"];
delete resHeaders["content-length"];
Sin esto, el proxy parece funcionar pero rompe cualquier cliente Python que use streaming. Nos costó horas de debug con logs detallados en el proxy para cazarlo.
Otro bug: el modelo de compresión
Hermes usa compresión de contexto — cuando la conversación es muy larga, la resume con un modelo barato. Teníamos configurado google/gemini-3-flash-preview para eso. El problema: ese modelo se enrutaba por el proxy de Anthropic, que solo acepta modelos de Claude. Resultado: HTTP 404.
La solución: forzar que el modelo de compresión use OpenRouter directamente.
# En config.yaml de Hermes
context_compression:
summary_model: "google/gemini-3-flash-preview"
summary_provider: "openrouter" # NO dejar en "auto"
El resultado
Ahora mi agente Hermes responde por Telegram usando Claude Sonnet 4, a través de mi suscripción Max. Sin API keys extra. Sin billing adicional. La misma suscripción que ya pago.
Johnny (Telegram) → "¿Qué entreno hoy?"
↓
Hermes Agent → consulta datos COROS, lee plan semanal
↓
Proxy OAuth → inyecta token, llama a Anthropic
↓
Claude Sonnet 4 → genera respuesta
↓
Johnny (Telegram) ← "Hoy toca carrera con cambios de ritmo: 3km calentamiento..."
El proxy corre como servicio systemd, arranca solo con el servidor, sobrevive a reboots. Los logs van a un archivo para debug. El token se relee en cada petición, así que si expira solo hay que abrir claude una vez para refrescarlo.
Limitaciones (las que hay que saber)
-
Rate limit compartido: Si usas Claude Code CLI al mismo tiempo que Hermes, compiten por el mismo rate limit.
-
Token con expiración: El token OAuth no es eterno. Cuando expira, hay que ejecutar
claudepara regenerarlo. En la práctica, dura bastante. -
Solo localhost: El proxy escucha en
127.0.0.1— no es accesible desde fuera del servidor. Esto es una feature de seguridad, no un bug. -
Solo modelos de Anthropic: No puedes pasar modelos de Google o OpenAI por este proxy. Solo Claude (Haiku, Sonnet, Opus).
Cómo montarlo tú
Si tienes una suscripción de Claude y un VPS:
1. Instala Claude Code CLI y loguéate:
npm install -g @anthropic-ai/claude-code
claude # sigue el login OAuth
2. Verifica que tienes el token:
python3 -c "import json; d=json.load(open('$HOME/.claude/.credentials.json')); print(d['claudeAiOauth']['accessToken'][:20]+'...')"
3. Crea el proxy (80 líneas de Node.js) y configúralo como servicio systemd.
4. Testa:
curl http://127.0.0.1:[IP]/v1/messages \
-H "content-type: application/json" \
-H "anthropic-version: 2023-06-01" \
-d '{"model":"claude-haiku-4-5-20251001","max_tokens":10,"messages":[{"role":"user","content":"hola"}]}'
Si ves una respuesta JSON con "content", funciona. Apunta tu app a http://127.0.0.1:[IP] y listo.
Todo el código del proxy y un script de instalación automática están disponibles. Si te interesa, escríbeme.
Lo que viene
Con Sonnet alimentando a Hermes, las respuestas son mucho más potentes. El siguiente paso es migrar completamente de OpenClaw a Hermes como mi agente principal — algo que ya está en marcha. También quiero explorar si el proxy puede servir para otras cosas: apps Next.js que usen la API, scripts de automatización, o incluso compartirlo con otros developers que tengan suscripción Max.
La suscripción que ya pagas puede hacer mucho más de lo que crees.