Plantilla de Changelog de API
Plantilla para documentar cambios de API incluyendo cambios breaking, nuevas capacidades, deprecaciones y correcciones.
Resumen
Los consumidores de API necesitan saber qué cambió, cuándo cambió, y si necesitan actuar. Un changelog no estructurado — o la ausencia de changelog — obliga a los consumidores a comparar tu API o descubrir cambios breaking en producción. Esta plantilla proporciona un formato estandarizado para documentar cada cambio de API con versión, fecha, severidad y guía de migración. Documentos relacionados: Cómo documentar una API con OpenAPI, Swagger UI y Redoc, Implementar logging y audit trails de API y la plantilla de aviso de deprecación para el ciclo largo.
Cuando Usar
- Para alternativas, consulta la Plantilla de Aviso de Deprecación de API.
Usa este recurso cuando:
- Lances una nueva versión o capacidad de API
- Deprecas o elimines un endpoint o campo
- Corrijas un bug que afecte el comportamiento de la API
- Publiques una actualización mensual o trimestral de API
Solución
# Changelog de API
## 2.5.0 — 2026-06-26
### Cambios Breaking
- **Eliminado:** `GET /v1/orders/{id}/items` — Usar `GET /v2/orders/{id}?expand=items` en su lugar
- **Cambiado:** Campo `total` renombrado a `totalAmount` en todas las respuestas de orden
- **Requerido:** Header `X-Request-ID` ahora obligatorio para todas las operaciones de escritura
### Nuevas Capacidades
- **Agregado:** `POST /v2/orders/bulk` — Crear hasta 100 órdenes en una sola solicitud
- **Agregado:** Campo `paymentStatus` en respuestas de orden (`pending`, `paid`, `failed`)
- **Agregado:** Evento de webhook `order.payment_failed` para notificaciones de pago fallido
### Correcciones
- **Corregido:** `GET /v2/products` ahora retorna arreglo vacío `[]` en lugar de `null` cuando no existen productos
- **Corregido:** Los campos de fecha ahora retornan consistentemente formato ISO 8601 con offset de zona horaria
### Deprecaciones
- **Deprecado:** Parámetro de consulta `customer_id` — Usar `customerId` en su lugar (retiro: 2026-10-01)
- **Deprecado:** Ruta base `v1` de API — Migrar a `v2` antes del 2026-12-01
## 2.4.0 — 2026-05-15
### Nuevas Capacidades
- **Agregado:** `PATCH /v2/orders/{id}` para actualizaciones parciales de orden
- **Agregado:** Headers de límite de tasa (`X-RateLimit-Limit`, `X-RateLimit-Remaining`) en todas las respuestas
### Correcciones
- **Corregido:** `500 Internal Server Error` en `POST /v2/orders` cuando el arreglo `items` estaba vacío
---
## Política de Versionado
Seguimos [Versionado Semántico](https://semver.org/lang/es/):
- **MAJOR:** Cambios breaking que requieren acción del consumidor
- **MINOR:** Nuevas capacidades, compatibles hacia atrás
- **PATCH:** Correcciones de bugs, compatibles hacia atrás
## Categorías de Cambio
| Categoría | Descripción | Acción Requerida del Consumidor |
|-----------|-------------|--------------------------------|
| Cambio Breaking | Las integraciones existentes pueden fallar | Sí — migración requerida |
| Nueva Capacidad | Nuevos endpoints, campos o comportamientos | Opcional — adoptar cuando este listo |
| Correccion | Bug corregido o comportamiento inconsistente | No — pero verificar si dependias del comportamiento anterior |
| Deprecación | Capacidad programada para eliminacion | Sí — antes de la fecha de retiro |
## Suscribirse a Cambios
- **Feed RSS:** https://developer.example.com/changelog.xml
- **Email:** Suscribirse en https://developer.example.com/subscribe
- **Webhook:** Configurar evento `api.changelog_published` en tu panel
- **Slack:** Unirse a #api-announcements en nuestro Slack comunitario
Ejemplo de Plantilla Extendida
Aquí hay un changelog más detallado con tres versiones, mostrando cómo las entradas se acumulan con el tiempo:
# Changelog de API
## 3.0.0 — 2026-09-01
### Cambios Breaking
- **Eliminado:** Todos los endpoints v1. Migrar a v2 o v3. Ver guía de migración.
- **Cambiado:** Autenticacion cambiada de API keys a OAuth 2.0 bearer tokens
- **Cambiado:** Formato de error estandarizado a RFC 7807 Problem Details
- **Eliminado:** `GET /v2/users/{id}/permissions` — Usar `GET /v2/users/{id}?expand=permissions`
- **Cambiado:** Paginación `offset`/`limit` reemplazada por `cursor`/`limit`
### Nuevas Capacidades
- **Agregado:** `POST /v3/webhooks` — Registrar endpoints de webhook programáticamente
- **Agregado:** Endpoint de exportación masiva `GET /v3/orders/export?format=csv`
- **Agregado:** Soporte de clave de idempotencia en todos los endpoints POST via header `Idempotency-Key`
### Correcciones
- **Corregido:** Los contadores de límite de tasa ahora se reinician correctamente a medianoche UTC en lugar de la hora local del servidor
- **Corregido:** `PATCH /v2/orders/{id}` ya no sobrescribe valores `null` cuando el campo se omite
### Deprecaciones
- **Deprecado:** Ruta base `v2` de API — Migrar a `v3` antes del 2027-03-01
- **Deprecado:** Header `X-API-Key` — Usar `Authorization: Bearer <token>` en su lugar
## 2.5.0 — 2026-06-26
### Cambios Breaking
- **Eliminado:** `GET /v1/orders/{id}/items` — Usar `GET /v2/orders/{id}?expand=items` en su lugar
- **Cambiado:** Campo `total` renombrado a `totalAmount` en todas las respuestas de orden
- **Requerido:** Header `X-Request-ID` ahora obligatorio para todas las operaciones de escritura
### Nuevas Capacidades
- **Agregado:** `POST /v2/orders/bulk` — Crear hasta 100 órdenes en una sola solicitud
- **Agregado:** Campo `paymentStatus` en respuestas de orden (`pending`, `paid`, `failed`)
- **Agregado:** Evento de webhook `order.payment_failed` para notificaciones de pago fallido
### Correcciones
- **Corregido:** `GET /v2/products` ahora retorna arreglo vacío `[]` en lugar de `null` cuando no existen productos
- **Corregido:** Los campos de fecha ahora retornan consistentemente formato ISO 8601 con offset de zona horaria
### Deprecaciones
- **Deprecado:** Parámetro de consulta `customer_id` — Usar `customerId` en su lugar (retiro: 2026-10-01)
- **Deprecado:** Ruta base `v1` de API — Migrar a `v2` antes del 2026-12-01
## 2.4.0 — 2026-05-15
### Nuevas Capacidades
- **Agregado:** `PATCH /v2/orders/{id}` para actualizaciones parciales de orden
- **Agregado:** Headers de límite de tasa (`X-RateLimit-Limit`, `X-RateLimit-Remaining`) en todas las respuestas
### Correcciones
- **Corregido:** `500 Internal Server Error` en `POST /v2/orders` cuando el arreglo `items` estaba vacío
Operar el Changelog
Un changelog que se escribe cuando alguien se acuerda es un changelog que deja de escribirse. Trátalo como un artefacto de release con dueño y un paso en el pipeline, no como un documento que alguien mantiene.
Quién escribe la entrada. La persona que despliega el cambio la redacta — conoce el impacto para el consumidor mejor que quien lo reconstruye después desde los commits. Un revisor (lead de API o developer advocate) la ajusta a las preguntas del consumidor: ¿dice qué hay que hacer, nombra la fecha de retiro, lo entiende quien se saltó dos versiones? Esa revisión son minutos, no días, si la entrada llega con el PR.
Cuándo se publica. Antes o con el despliegue, nunca después. Para cambios breaking y deprecaciones la entrada sale antes del cambio — esa es la notificación, no un informe de ella. Una deprecación publicada el mismo día en que el header empieza a volar da cero aviso al consumidor; el periodo de aviso es el punto.
Dónde vive. Un archivo renderizado en el sitio de docs es la base. RSS y email llegan a los consumidores que nunca recargarán la página, y el webhook api.changelog_published existe para equipos que quieren automatizar su propio triage. Las notas internas de release se quedan internas — mezclar trabajo de CI en la página del consumidor enseña a los lectores a dejar de leerla.
Qué se registra por entrada. Versión, fecha, categoría y la acción que el consumidor debe tomar — “usar GET /v2/orders/{id}?expand=items” — no solo qué cambió. Si una entrada no le dice al lector si necesita actuar, ha fallado en su única tarea.
Decisiones: Breaking vs No-Breaking
La línea que le importa al consumidor es si su código cliente sigue funcionando sin cambios. Todo lo demás es detalle.
| Cambio | ¿Breaking? | Por qué |
|---|---|---|
| Eliminar un endpoint o campo | Sí | Los clientes que lo llaman/leen se rompen |
| Renombrar un campo o parámetro | Sí | Renombrar es eliminar + añadir |
| Cambiar tipo o formato de un campo | Sí | total: 42 → total: "42.00" rompe parsers |
| Hacer obligatorio un campo opcional | Sí | Los requests existentes empiezan a fallar |
| Cambiar el mecanismo de paginación | Sí | offset→cursor es un cambio de contrato |
| Añadir endpoint, campo o valor enum | Normalmente no | Salvo clientes que validan respuestas estrictamente — dilo en la entrada |
| Añadir un header obligatorio | Sí | Los requests viejos ahora se rechazan |
| Endurecer un rate limit | Zona gris | Documéntalo bien aunque sea cambio de política, no de esquema |
| Corregir un bug del que dependían | Zona gris | Si el comportamiento buggy estaba documentado, es breaking; si no, corrige y nota la inconsistencia |
| Deprecar sin eliminar | No | Es una promesa sobre el futuro — para eso existe la categoría |
Ante la duda real, trátalo como breaking. El coste de anunciar de más es un changelog más ruidoso; el de anunciar de menos son consumidores rotos que dejan de confiar en el changelog — y cuando esa confianza se va, la página es decoración.
Automatización de Changelog
Generar changelogs manualmente es propenso a errores. Usa convenciones de mensajes de commit y herramientas para producir changelogs automatica o semi-automaticamente.
Conventional Commits
Estructura los mensajes de commit para que una herramienta pueda parsearlos:
feat(api): agregar endpoint de creación masiva de ordenes
POST /v2/orders/bulk acepta hasta 100 órdenes en una solicitud.
Retorna 207 Multi-Status con resultados por orden.
BREAKING CHANGE: campo total renombrado a totalAmount en respuestas de orden
Script de Node.js para Generar Changelog desde Tags de Git
const { execSync } = "child_process";
function generateChangelog(fromTag, toTag) {
const log = execSync(
`git log ${fromTag}..${toTag} --pretty=format:"%s|%H" --no-merges`
).toString();
const entries = log.split("\n").map((line) => {
const [message, hash] = line.split("|");
return { message: message.trim(), hash };
});
const breaking = entries.filter((e) =>
e.message.includes("BREAKING CHANGE") || e.message.startsWith("feat!")
);
const features = entries.filter((e) =>
e.message.startsWith("feat") && !e.message.includes("BREAKING")
);
const fixes = entries.filter((e) => e.message.startsWith("fix"));
const deprecations = entries.filter((e) =>
e.message.startsWith("deprecate") || e.message.includes("DEPRECATED")
);
let output = `## ${toTag} — ${new Date().toISOString().split("T")[0]}\n\n`;
if (breaking.length) {
output += "### Cambios Breaking\n";
breaking.forEach((e) => {
output += `- **Cambiado:** ${e.message.replace(/BREAKING CHANGE:\s*/, "")}\n`;
});
output += "\n";
}
if (features.length) {
output += "### Nuevas Capacidades\n";
features.forEach((e) => {
output += `- **Agregado:** ${e.message.replace(/^feat\([^)]+\):\s*/, "")}\n`;
});
output += "\n";
}
if (fixes.length) {
output += "### Correcciones\n";
fixes.forEach((e) => {
output += `- **Corregido:** ${e.message.replace(/^fix\([^)]+\):\s*/, "")}\n`;
});
output += "\n";
}
if (deprecations.length) {
output += "### Deprecaciones\n";
deprecations.forEach((e) => {
output += `- **Deprecado:** ${e.message.replace(/^deprecate\([^)]+\):\s*/, "")}\n`;
});
}
return output;
}
console.log(generateChangelog("v2.4.0", "v2.5.0"));
Herramientas que Generan Changelogs
| Herramienta | Lenguaje | Enfoque |
|---|---|---|
| semantic-release | JavaScript | Parsea conventional commits, genera releases automaticamente |
| conventional-changelog | JavaScript | CLI para generar changelogs desde historial de commits |
| auto-changelog | JavaScript | CLI simple, genera Markdown desde git log |
| git-cliff | Rust | Generador de changelog configurable desde commits |
| changeloguru | Go | Conventional commits a changelog |
Headers de Deprecación en Práctica
Envía headers HTTP en respuestas de API deprecadas para que los consumidores detecten la deprecación programáticamente. Deprecation y Sunset siguen RFC 8594 y la relación de enlace deprecation apunta a la guía de migración:
HTTP/1.1 200 OK
Content-Type: application/json
Deprecation: true
Sunset: Sat, 01 Oct 2026 00:00:00 GMT
Link: <https://docs.example.com/api-migration>; rel="deprecation"
Verificar Headers de Deprecacion en Código Cliente
import requests
response = requests.get("https://api.example.com/v1/orders", headers={
"Authorization": "Bearer token123"
})
if response.headers.get("Deprecation") == "true":
sunset = response.headers.get("Sunset", "fecha desconocida")
link = response.headers.get("Link", "")
print(f"ADVERTENCIA: Este endpoint está deprecado. Retiro: {sunset}")
print(f"Guia de migración: {link}")
const response = await fetch("https://api.example.com/v1/orders", {
headers: { Authorization: "Bearer token123" }
});
const deprecation = response.headers.get("Deprecation");
if (deprecation === "true") {
const sunset = response.headers.get("Sunset");
const link = response.headers.get("Link");
console.warn(`Endpoint deprecado. Retiro: ${sunset}`);
console.warn(`Guia de migración: ${link}`);
}
Archivado y Retención
La página del changelog no puede crecer para siempre — una API de tres años con releases mensuales produce una página que nadie desplaza. Define las reglas de retención una vez y documéntalas en la política de versionado:
- Ventana activa: mantén los últimos 12 meses de entradas en la página principal. Los consumidores enterprise con ciclos largos sí miran tan atrás; las entradas más viejas van a una página de archivo enlazada desde la cabecera.
- Formato del archivo: misma estructura, mismo orden por severidad, solo más viejo. No degrades las entradas archivadas a una nota al pie — un consumidor que actualiza cruzando un año lee el archivo con el mismo cuidado que la página activa.
- Memoria de retiros: mantén visibles las fechas de retiro en el archivo. Cuando alguien corre un cliente dos majors atrás, “v1 deprecado, retiro 2026-12-01” es la información que busca.
- Retención del feed: las entradas RSS pueden caer a los 90 días — el feed es notificación; el archivo es historia.
- Nunca reescribas entradas publicadas: corrige un error con una nota fechada (“Corrección 2026-10-26: el renombre
totalAmountllegó en 2.5.0, no en 2.4.0”), no con una edición silenciosa. Los consumidores comparan la página; un cambio callado se lee como engaño.
Revisión del Changelog Antes de Publicar
Antes de cada release, la entrada debería pasar una revisión de dos minutos:
- ¿Cada cambio breaking dice qué hacer en su lugar? “Eliminado
X” sin “usaY” es un ticket de soporte, no una entrada de changelog. - ¿Toda deprecación tiene fecha de retiro? Sin fecha no hay urgencia de migración.
- ¿Puede un consumidor que se saltó tres versiones reconstruir qué hacer? Las entradas deben componerse.
- ¿Salió algo visible al consumidor sin entrada? Compara el changelog con el despliegue real.
- ¿Fecha y versión consistentes en cabecera y cuerpo?
El revisor no necesita entender la feature — necesita creer que un consumidor podría actuar solo con la entrada. Ese es el listón.
Estándares de Formato de Changelog
| Elemento | Estándar | Ejemplo |
|---|---|---|
| Número de versión | Versionado Semantico | 2.5.0 |
| Formato de fecha | ISO 8601 (YYYY-MM-DD) | 2026-06-26 |
| Verbo de entrada | Pasado, en negrita | **Agregado:**, **Corregido:** |
| Marcador de cambio breaking | Primera seccion bajo cada versión | ### Cambios Breaking |
| Retiro de deprecacion | Fecha ISO 8601 entre parentesis | (retiro: 2026-10-01) |
| Enlace de migración | URL o referencia a endpoint | Usar GET /v2/orders/{id}?expand=items |
Explicacion
El changelog usa una jerarquia de versión-fecha-entrada para que los consumidores puedan escanear su versión actual y ver todo lo que cambió desde entonces. Los cambios breaking se listan primero porque demandan atención inmediata. Cada entrada incluye un verbo (Agregado, Eliminado, Corregido, Deprecado) para que los consumidores entiendan la naturaleza del cambio de un vistazo. La seccion de politica de versionado reduce confusion sobre lo que significa cada número de versión.
Variantes
| Contexto | Enfoque | Notas |
|---|---|---|
| API Pública | Changelog completo con RSS/email | Los consumidores se autoserven, reducen tickets de soporte |
| API Interna | Slack + resumen corto | Más rápido, menos ceremonia |
| API de Partners | Email + enlace a guía de migración | Los partners necesitan comunicación premium |
| API GraphQL | Diff de esquema + changelog | Usar directiva @deprecated en esquema junto al changelog |
Lo que funciona
- Publicar el changelog antes de desplegar el cambio — no después de que los consumidores reporten problemas
- Agrupar entradas por severidad — cambios breaking primero, luego capacidades, luego correcciones
- Incluir instrucciones de migración con cada cambio breaking, no solo una descripcion
- Enlazar a documentación para capacidades nuevas complejas en lugar de explicar en el changelog
- Archivar versiones antiguas pero mantenerlas accesibles — los clientes enterprise pueden estar varias versiones atrás
- Usar conventional commits para que los changelogs se generen o verifiquen automaticamente
- Enviar headers de deprecacion en respuestas de API para que el codigo cliente detecte y advierta
Errores Comunes
- Mezclar correcciones de bugs y cambios breaking sin categorización clara
- Escribir “varias correcciones de bugs” en lugar de listar correcciones especificas que les importan a los consumidores
- Publicar changelogs días después del despliegue — los consumidores ya estan rotos
- No versionar el changelog mismo — si el changelog cambia, los consumidores pierden confianza
- Olvidar documentar campos eliminados — los consumidores descubren datos faltantes solo en producción
- Omitir la fecha de retiro para deprecaciones — los consumidores no saben cuánto tiempo tienen
- No enlazar a guías de migración desde la entrada del changelog
- Usar formatos de fecha inconsistentes entre versiones — usar ISO 8601
- Enterrar los cambios breaking al final de una entrada de versión en lugar de listarlos primero
Lectura Adicional
- Keep a Changelog — el estándar de formato
- Semantic Versioning — el esquema que el changelog trackea
- RFC 8594 — Sunset Header — deprecación machine-readable
Preguntas frecuentes
Hasta dónde atrás debería ir el changelog?
Mantener al menos los últimos 12 meses de cambios en linea. Archivar versiones mas antiguas en una página separada. Los clientes enterprise con ciclos de adquisicion largos pueden necesitar referenciar cambios de hace un año.
Deberia documentar cambios solo internos?
No. El changelog es para consumidores. La refactorización interna, cambios de CI/CD o actualizaciones de infraestructura pertenecen a notas de lanzamiento internas, no al changelog publico de API.
Que pasa si una correccion de bug cambia comportamiento en el que algunos consumidores dependian?
Documentarlo como un cambio breaking si el comportamiento anterior estaba documentado. Si el comportamiento anterior era un bug, documentarlo como una correccion pero incluir una nota: "El comportamiento anterior era involuntario e inconsistente con la documentación."
El changelog debería ser un solo archivo o una página por versión?
Para APIs pequenas, un solo archivo Markdown funciona bien. Para APIs con releases frecuentes, usar una página por versión mayor con un índice. Esto mantiene la página cargable y buscable.
Como manejo versiones pre-release?
Usar etiquetas pre-release de SemVer: 3.0.0-beta.1, 3.0.0-rc.1. Documentarlas en el changelog con una nota de que la API puede cambiar antes del release estable.
Deberia incluir mejoras de rendimiento en el changelog?
Solo si cambian comportamiento observable — por ejemplo, una garantia de menor latencia o un nuevo header de cache. Optimizaciones internas de rendimiento que no afectan a los consumidores pertenecen a notas internas.
Como automatizo la publicacion del changelog?
Usar un pipeline CI/CD que se ejecute al crear un tag: generar la seccion del changelog desde los commits, agregarla al archivo de changelog, publicar en el sitio de docs y enviar una notificación a los canales suscritos.
Recursos Relacionados
Plantilla del Ciclo de Vida de APIs
Una plantilla de checklist lista para copiar para gestionar la deprecación de APIs, las transiciones de versionado y los cierres seguros.
DocPlantilla de Aviso de Deprecación de API
Plantilla para comunicar deprecaciones de API, cambios breaking y plazos de retiro a los consumidores.
DocPlantilla de Especificación Técnica
Usa esta plantilla de especificación técnica para documentar requisitos, decisiones de diseño, arquitectura, contratos de API y criterios de aceptación.
DocPlantilla de Definicion de SLA
Plantilla para definir y documentar Acuerdos de Nivel de Servicio incluyendo objetivos de uptime, tiempos de respuesta, presupuestos de error y procedimientos de escalamiento.
DocPlantilla de Política de Rate Limiting de API
Plantilla para definir límites de tasa de API por tier de consumidor, incluyendo márgenes de ráfaga, períodos de cuota y rutas de escalado.
GuideGuía Completa de Estrategias de Versionado de APIs
Compara versionado por URI, header, query-param y negociación de contenido para REST, más evolución de esquema GraphQL y migración.