Los apuntes explican el porqué; esto es el qué. Está pensado para lo que no se te queda porque no lo escribes nunca: nombres de campos, valores admitidos y formas de retorno. El examen no te pide escribir código, pero sí reconocer el nombre correcto entre cuatro que suenan parecido.
Messages API POST /v1/messages
| Campo | Obligatorio | Notas |
model | Sí | ID de snapshot. Los IDs sin fecha siguen siendo snapshots fijos, no punteros móviles |
messages | Sí | Solo roles user y assistant. Turnos consecutivos del mismo rol se combinan |
max_tokens | Sí | 0 sirve para precalentar caché sin generar respuesta |
system | No | Parámetro top-level, string o array de bloques. No existe rol system |
tools, tool_choice | No | Ver sección de tool use |
stream | No | true activa SSE |
thinking, output_config | No | Ver razonamiento y salida estructurada |
temperature, top_p, top_k, stop_sequences | No | Muestreo |
metadata, service_tier, inference_geo | No | inference_geo: "global" por defecto o "us", con recargo |
Lo que se preguntaQue el system prompt es un parámetro aparte y que no existe el rol system dentro de messages. Es la diferencia más citada frente a otras APIs de chat.
Los modos de interacción
Un desarrollador llega a Claude por una API REST, normalmente a través de un SDK. La elección del modo se decide con dos preguntas: ¿hay alguien esperando? y ¿es tiempo real o volumen offline?
| Modo | Cuándo |
| Síncrono | Alguien espera y la respuesta es corta. Lo más simple |
| Streaming | Alguien espera y la respuesta es larga: compra latencia percibida a cambio de ensamblar tú la respuesta |
| Async / await | Nadie espera en ese instante, pero sigue siendo tiempo real: concurrencia sin bloquear |
| Batch | Nadie espera y es volumen offline: menor coste por token, latencia no determinista |
Lo que se preguntaQue lanzar llamadas síncronas en paralelo no es batch: da concurrencia, no descuento. Y que streaming no acelera nada — mejora la latencia percibida.
La ventana de contexto y sus dos formas de romperse
Es un presupuesto fijo de tokens que sostiene la petición entera de golpe: system, historial, tools, documentos y la generación. Falla de dos maneras distintas, y el examen puede pedir distinguirlas:
| Situación | Qué ocurre |
| La entrada ya no cabe | Error antes de generar. No hay respuesta parcial |
| Se toca el techo a mitad de generación | Salida truncada con stop_reason: model_context_window_exceeded |
Lo que se preguntaQue gestionar el historial es trabajo de la aplicación, no de la API. Nadie poda por ti: compactación, pruning y subagentes son decisiones tuyas.
Valores de stop_reason
| Valor | Significa | Qué haces |
end_turn | Terminó de forma natural | Cerrar el turno |
tool_use | Pide ejecutar una o más tools | Ejecutar y devolver tool_result; el bucle continúa |
max_tokens | Salida truncada | Puede romper JSON estricto. Reintentar con más presupuesto |
stop_sequence | Encontró una secuencia de parada | Tratar según tu protocolo |
refusal | Rechazó responder | Devuelve 200 y se factura. Prevalece sobre el esquema |
pause_turn | Pausa en operación larga | Continuar el turno |
model_context_window_exceeded | Se pasó de ventana | Compactar o reducir contexto |
Lo que se preguntatool_use frente a end_turn como control del bucle agéntico, y que refusal y max_tokens son los dos casos en que la salida estructurada puede no cumplir el esquema.
Streaming stream: true
message_start
content_block_start // por cada bloque, con su index
content_block_delta // N veces
content_block_stop // AQUÍ el bloque está cerrado
message_delta // usage acumulativo
message_stop // AQUÍ el turno se confirma
| Tipo de delta | Contenido |
text_delta | Fragmento de texto |
input_json_delta | JSON parcial del input de una tool. No parsear hasta content_block_stop |
thinking_delta | Fragmento de razonamiento |
signature_delta | Justo antes de cerrar un bloque de thinking |
Lo que se preguntaTres cosas: los errores llegan como event: error después de un HTTP 200; los bloques de tool use y thinking no se recuperan parcialmente (solo se reanuda desde el último bloque de texto); y un error de tool use al reintentar suele trazar a un bloque a medio construir, no al esquema.
Message Batches
| Concepto | Valor |
| Descuento | 50% input y output |
| Límite por batch | 100.000 requests o 256 MB |
| Ventana | Mayoría menos de 1 h · resultados al terminar o a las 24 h · expiran a las 24 h |
| Resultados descargables | 29 días |
processing_status | Solo in_progress y ended |
| Resultado por request | succeeded · errored · canceled · expired (los tres últimos no se facturan) |
| No soportado | stream: true, max_tokens: 0 |
| Disponible en | Solo Claude API y Claude Platform on AWS |
Lo que se preguntaQue solo hay dos estados de batch, que no admite streaming, y que lanzar llamadas síncronas en paralelo no es batching porque no baja el coste por token.
Prompt caching cache_control
{ "type": "text", "text": "...",
"cache_control": { "type": "ephemeral", "ttl": "1h" } }
// "ephemeral" es el único tipo. ttl opcional: por defecto 5 min
| Parámetro | Valor |
| TTL | 5 min por defecto · 1 h extendido |
| Breakpoints máximos | 4 (el automático consume uno) |
| Lookback | 20 bloques por breakpoint |
| Precio de escritura | 1,25× (5 min) · 2× (1 h) |
| Precio de lectura | 0,1× |
| Jerarquía del prefijo | tools → system → messages |
| Mínimo cacheable | Entre 512 y 4.096 tokens según modelo |
Lo que se preguntaQue cambiar tools invalida todo el prefijo, que cambiar el nivel de effort también rompe la caché porque se renderiza en el prompt, y el fallo silencioso: por debajo del mínimo no cachea y no da error — se detecta con ambos contadores de caché a cero en usage.
Razonamiento y effort
| Parámetro | Valores | Notas |
thinking.type | adaptive | El modelo decide. En los modelos actuales está siempre activo; desactivarlo da 400 |
thinking.type | enabled + budget_tokens | Deprecado. Rechazado con 400 en modelos recientes |
display | summarized · omitted | Se factura igual en ambos casos |
output_config.effort | max · xhigh · high · medium · low | Por defecto high. Señal conductual, no presupuesto |
El principio de fondoElegir modelo y elegir modo de razonamiento son dos palancas separadas y componibles. La regla es de suelo hacia arriba: el modelo más pequeño y el razonamiento y prompting más simples que pasen tu eval, y añadir capacidad solo donde la eval diga que hace falta. No al revés.
Lo que se preguntaQue los tokens de razonamiento se facturan como output y cuentan contra max_tokens aunque no se devuelva el texto, y que los bloques thinking llevan signature y deben devolverse sin modificar o la siguiente petición falla.
Salida estructurada
Dos mecanismos: JSON outputs (esquema en output_config.format, restringe la respuesta final) y strict tool use (strict: true en una tool, valida los argumentos). Ambos por decodificación restringida.
| Límite por request | Valor |
Tools con strict | 20 |
| Parámetros opcionales, total | 24 |
| Parámetros con tipos unión | 16 |
| Timeout de compilación | 180 s |
| Caché de gramática | 24 h desde el último uso |
| Admite | No admite (400) |
tipos básicos, enum escalar, const, anyOf, $ref interno, default, required, formatos de string | esquemas recursivos, $ref externo, minimum/maximum, minLength/maxLength, lookahead en pattern |
Lo que se preguntaQue el prefill ya no vale para forzar JSON, que el casing de los enum no está garantizado, que las propiedades required salen primero en el orden, y que citations más structured outputs dan 400.
Errores y estrategia de reintento
| Código | Tipo | ¿Reintentable? |
| 400 | invalid_request_error | No — arreglar la petición |
| 401 / 403 | auth / permisos | No — credencial |
| 413 | request_too_large | No — trocear |
| 429 | rate_limit_error | Sí, con backoff y respetando retry-after |
| 500 | api_error | Sí |
| 504 | timeout_error | Sí |
| 529 | overloaded_error | Sí — sobrecarga global, no tuya |
La clasificación de fallos
- Primera pregunta ante cualquier fallo: ¿esperar y reintentar podría resolverlo?
- Si sí → backoff exponencial con tope y presupuesto de reintentos. Nunca un bucle inmediato, que solo agrava el problema.
- Si no → fallback con nombre. Sin él, la excepción no gestionada se convierte en el comportamiento por defecto, y una respuesta mala tumba el flujo entero.
- Fallo de tool → vuelve al modelo con la bandera de error puesta, nunca escondido tras un resultado vacío que el modelo confundiría con datos.
Los SDK oficiales ya reintentan con backoff exponencial, 2 reintentos por defecto, respetando retry-after.
Evals: método de grading según la salida
| Forma de la salida | Grader |
| Hay una forma correcta | Exact match |
| Salida estructurada | Comprobación por código |
| Calidad abierta | Juez LLM, calibrado contra casos etiquetados por humanos antes de fiarte de él |
Orden de preferencia oficial: código → LLM → humano. Sobre el humano, la doc dice literalmente «evítalo si puedes». Y el principio de diseño: más casos con señal algo peor y grading automático supera a pocos casos calificados a mano.
Lo que se preguntaQue la eval se escribe primero: identificar el comportamiento esperado te obliga a definir el éxito mientras el diseño todavía puede cambiar. Una eval convierte «está terminado» de una sensación en una puntuación sobre un conjunto fijo de casos.
Niveles de test y qué caza cada uno
| Nivel | Caza |
| Unit | Errores de lógica dentro de un componente |
| Funcional | Que un componente cumple su especificación |
| Integración | La costura: el traspaso entre dos componentes que pasan por separado |
| End-to-end | Todo el flujo. Dice que algo falla, no dónde |
El patrón de diagnósticoUnits y funcionales en verde con el e2e en rojo significa que la rotura está en un traspaso, no dentro de un componente — y por definición eso es lo que cubre un test de integración. La respuesta completa tiene dos mitades: corregir en la costura y añadir el test de integración que faltaba. Una traza te dice qué paso produjo el mal resultado, que es lo que convierte un día de investigación en un arreglo corto.
El mismo instinto rige la recuperación de información: una sola búsqueda para consultas de un solo dato, búsqueda a lo largo de varias iteraciones cuando la pregunta es genuinamente multi-paso.
Hooks
| Evento | Para qué |
PreToolUse | Validar o bloquear antes de ejecutar |
PostToolUse | Añadir contexto, reemplazar la salida, auditoría |
UserPromptSubmit | Interceptar la entrada del usuario |
SubagentStart / SubagentStop | Ciclo de vida de subagentes |
PreCompact | Antes de compactar (trigger: manual o auto) |
SessionStart / SessionEnd / Stop / Notification | Ciclo de vida y avisos |
Forma de retorno de PreToolUse
{ "permissionDecision": "deny", // allow | deny | ask | defer
"permissionDecisionReason": "...",
"updatedInput": { ... } } // opcional
- Exit 2 = error bloqueante, no anulable ni con un
allow.
- Silencio no es aprobación: un hook puede denegar, pero callarse deja seguir el flujo normal de permisos.
- Los hooks corren en tu proceso, fuera de la ventana de contexto: no consumen tokens salvo lo que devuelvan.
Lo que se preguntaQue el hook es el mecanismo de enforcement determinista frente a una instrucción, que PreToolUse es donde se pone la frontera de acción que bloquea y registra antes de ejecutar, y que PostToolUse es el sitio del log de auditoría para un cliente regulado.
Agent SDK
| Opción | Qué hace |
allowedTools | Auto-aprobación. Debe incluir la tool de spawn para usar subagentes |
maxTurns | Cuenta solo turnos con tool use |
maxBudgetUsd | Corta por coste; incluye el gasto de los subagentes |
systemPrompt | Sin él, prompt mínimo. Con preset, el prompt completo del CLI. O el tuyo |
settingSources | Controla si se carga CLAUDE.md. Vacío lo desactiva |
resume / forkSession | Retomar una sesión concreta / ramificarla en una nueva |
permissionMode | default · acceptEdits · plan · auto · dontAsk · bypassPermissions |
AgentDefinition de un subagente
{ "description": "...", // obligatorio
"prompt": "...", // obligatorio - lo ÚNICO que cruza del padre
"tools": [...], // si se omite, hereda todas
"model": "inherit", // o un modelo concreto
"skills": [...] } // los subagentes NO precargan skills
Lo que se preguntaQue maxTurns no cuenta los turnos sin tools, que el presupuesto incluye a los subagentes, y que el subagente no hereda historial: solo el string del prompt.
MCP
| Primitiva | La controla | Métodos |
| Tools | El modelo | tools/list · tools/call |
| Resources | La aplicación (solo lectura) | resources/list · resources/read |
| Prompts | El usuario | prompts/list · prompts/get |
| Decisión | Opciones |
| Transporte | stdio (local) · Streamable HTTP (remoto o multi-desarrollador) |
| Scope en Claude Code | local (personal) · project (.mcp.json, versionado) · user (todos tus proyectos) |
| Carga diferida | defer_loading en el toolset: difiere el contexto, no el payload |
Nomenclatura en Claude Code: tools mcp__servidor__tool · prompts /mcp__servidor__prompt · resources @servidor:proto://ruta.
Lo que se preguntaQuién controla cada primitiva, que stdio no debería usar OAuth porque toma credenciales del entorno, y que un servidor stdio en .mcp.json parece compartible y no lo es.
Límites y contadores
| Concepto | Valor |
| Tamaño de request | Messages 32 MB · Batch 256 MB · Files 500 MB |
| Timeout no-streaming | 10 minutos |
| Contar tokens | POST /v1/messages/count_tokens — gratis, rate limit independiente |
| ITPM | input más creación de caché. Las lecturas de caché no cuentan |
| OTPM | Tokens realmente generados. max_tokens no influye |
| Cabeceras | request-id en toda respuesta · anthropic-ratelimit-*-{limit,remaining,reset} |
| Degradación de selección de tools | Por encima de 30-50 tools disponibles |
| Coste de una imagen | ⌈ancho/28⌉ × ⌈alto/28⌉ visual tokens |
| Techo de imagen | Alta resolución 2576 px / 4784 tokens · estándar 1568 px / 1568 |
| Coste de multi-agente | Multiplica por el número de subagentes: ~15× en el caso publicado |
Lo que se preguntaQue no puedes presupuestar lo que no mides: hay que instrumentar coste en tokens, latencia y tasa de error en cada llamada y luego ajustar una palanca elegida, en vez de adivinar mirando la factura. Y que el patrón orquestador-trabajadores solo se gana ese coste en tareas que se dividen en partes paralelas independientes, no en trabajo fuertemente acoplado que un solo agente resuelve por una fracción.