Plantilla de Aviso de Deprecación de API
Plantilla para comunicar deprecaciones de API, cambios breaking y plazos de retiro a los consumidores.
Resumen
Las APIs evolucionan. Los campos se renombran, los endpoints se reemplazan y las versiones antiguas se retiran. Sin un aviso de deprecación claro, los consumidores descubren los cambios breaking solo después de que sus integraciones fallan. Esta plantilla te da un formato estándar para anunciar deprecaciones, comunicar plazos y guiar a los consumidores a través de las migraciones. Recursos relacionados: Stream de salida LLM con Server-Sent Events (SSE), Cómo documentar una API con OpenAPI, Swagger UI y Redoc e Implementar logging y audit trails de API.
Cuándo Usar
- Para alternativas, consulta la Plantilla de Changelog de API.
Usa este recurso cuando:
- Elimines o renombres un endpoint, campo o parámetro de API
- Cierres una versión completa de API
- Migres consumidores de un servicio legacy a un reemplazo
- Actualices mecanismos de autenticación que rompan clientes existentes
Solución
# Aviso de Deprecación de API: `<Endpoint / Campo / Versión>`
**API:** `api.ejemplo.com/v1/...`
**Deprecado Desde:** `2026-07-01`
**Fecha de Retiro:** `2026-10-01` (aviso de 92 días)
**Severidad:** `Cambio Breaking` | `Deprecación No Breaking`
## Qué Está Cambiando
### Antes
GET /v1/orders?customer_id=123 Response: { “order_id”: “abc”, “total”: 100.00 }
### Después
GET /v2/orders?customerId=123 Response: { “orderId”: “abc”, “totalAmount”: 100.00 }
## Por Qué Este Cambio
- Alinear los nombres de campos con el estándar camelCase de la empresa
- Consolidar los modelos de datos v1 y v2 para reducir mantenimiento
- Eliminar campos deprecados que exponen identificadores internos
## Pasos de Migración
1. **Actualizar nombres de campos:** Renombrar `customer_id` a `customerId`, `order_id` a `orderId`
2. **Actualizar parsing de respuesta:** Reemplazar `total` por `totalAmount` (mismo tipo de dato)
3. **Cambiar endpoint:** Cambiar la ruta base de `/v1/orders` a `/v2/orders`
4. **Probar en sandbox:** Validar la integración contra `sandbox-api.ejemplo.com/v2`
5. **Desplegar a producción:** Antes del `2026-10-01`
## Cronograma
| Hito | Fecha | Acción Requerida |
|------|-------|-------------------|
| Aviso Enviado | 2026-07-01 | Revisar guía de migración |
| Sandbox Disponible | 2026-07-01 | Comenzar pruebas de endpoints v2 |
| v1 Marcado Deprecado | 2026-07-01 | Monitorear headers de deprecación |
| Recordatorio Final | 2026-09-01 | Completar migración o solicitar extensión |
| Retiro de v1 | 2026-10-01 | v1 retorna 410 Gone |
## Soporte y Contacto
- **Guía de Migración:** https://docs.ejemplo.com/api-migration
- **Entorno Sandbox:** https://sandbox-api.ejemplo.com
- **Email de Soporte:** api-soporte@ejemplo.com
- **Horarios de Atención:** Cada martes 10:00 UTC
## Excepciones
Si no puedes migrar antes de la fecha de retiro, contáctanos en api-soporte@ejemplo.com con:
- Tu caso de uso
- Cronograma estimado de migración
- Bloqueantes que impidan la migración a tiempo
Explicación
La plantilla separa qué está cambiando de por qué y cómo migrar. La tabla de cronograma crea responsabilidad y elimina ambigüedad sobre las fechas límite. Incluir un entorno sandbox y contacto de soporte reduce la fricción para los consumidores. La sección de excepciones reconoce que no todos los consumidores pueden migrar en el mismo plazo.
Cómo Adaptar Esta Plantilla
El mismo esqueleto funciona para cada deprecación, pero tres decisiones cambian lo que envías:
Severidad. Un cambio breaking (endpoint eliminado, campo renombrado, cambio de esquema de autenticación) necesita el aviso completo: pasos de migración, tabla de cronograma, enlace a sandbox y un contacto con nombre. Una deprecación no breaking (un campo nuevo preferido junto al antiguo, un parámetro opcional que desaparece) puede reducirse a un aviso más corto: qué cambió, cuándo desaparece y dónde leer más. No des la voz de alarma en vano: si marcas cada deprecación como “Cambio Breaking”, los consumidores dejan de leer el banner.
Audiencia. Los consumidores externos necesitan fechas con las que puedan planificar — trimestres, no semanas — y un humano al que escalar. Los consumidores internos toleran ventanas de 30 días y un post en Slack, pero siguen necesitando los pasos de migración; el “ya lo resolveremos” es la razón por la que las v1 internas viven para siempre. Si tu API tiene ambas audiencias, escribe primero el aviso público y recórtalo para el canal interno, no al revés.
Canal. El email llega a las personas que se registraron; los headers de respuesta llegan a las integraciones que realmente te llaman; los dashboards llegan a los humanos que depuran a las 2 de la madrugada. Necesitas los tres, y por eso el plan de comunicación de abajo los escalona en lugar de enviar un solo anuncio.
Para calibrar, mira cómo lo anuncian las APIs públicas: la documentación de versionado de Stripe trata cada cambio como fechado y opt-in, GitHub publica posts de deprecación con meses de antelación y horas de corte UTC exactas, y los servicios de API de Google publican calendarios de deprecación explícitos por versión. El patrón común es que la fecha límite es una promesa: elige una fecha que realmente puedas cumplir.
Avisos de Deprecación Reales
Tres deprecaciones públicas que vale la pena estudiar antes de escribir la tuya:
GitHub: autenticación por contraseña para operaciones Git. GitHub anunció en 2019 que la autenticación por contraseña para la API moriría, dio más de un año de aviso y — la parte que vale robarse — ejecutó brownouts programados: durante unas horas cada vez, rechazaron los requests autenticados con contraseña para que las integraciones fallaran ruidosamente antes del corte real. Quien siguiera usando contraseña lo descubrió durante el brownout, no después del retiro. El corte final se movió una vez, y la nueva fecha se anunció de la misma forma.
Kubernetes: la política de deprecación es el aviso en sí. Kubernetes publica una política de deprecación versionada: las APIs beta reciben aproximadamente 9 meses o 3 releases de soporte tras la deprecación, las versiones GA más tiempo. Los consumidores no necesitan un email para planificar; la política ES el cronograma. Es el estado ideal para una API con una base grande de consumidores: las reglas de deprecación son públicas, versionadas y aburridamente predecibles.
Stripe: versiones fechadas en lugar de retiro. Stripe evita el problema por completo para cambios pequeños: cada cuenta queda anclada a la versión de API vigente cuando fue creada, y los consumidores actualizan a su propio ritmo. También retiran versiones antiguas eventualmente, pero el anclaje de versión hace que el aviso de deprecación aterrice en un codebase que ya está probando la versión nueva, no en uno que acaba de romperse.
El patrón en los tres casos: la fecha límite es real, la advertencia llega por el canal que el consumidor realmente usa, y hay un ensayo (brownout, versión anclada, política publicada) antes del corte definitivo.
Implementación de Headers de Deprecación
Los headers HTTP Deprecation y Sunset (estándar IETF en borrador) permiten que el código cliente detecte endpoints deprecados programáticamente. Impleméntalos en tu middleware de API.
Middleware en Express.js
function deprecationMiddleware(req, res, next) {
const deprecatedPaths = {
"/v1/orders": { sunset: "2026-10-01", replacement: "/v2/orders" },
"/v1/products": { sunset: "2026-10-01", replacement: "/v2/products" },
};
const match = Object.keys(deprecatedPaths).find((path) =>
req.path.startsWith(path)
);
if (match) {
const info = deprecatedPaths[match];
res.setHeader("Deprecation", "true");
res.setHeader("Sunset", new Date(info.sunset).toUTCString());
res.setHeader(
"Link",
`<https://docs.ejemplo.com/api-migration>; rel="deprecation"`
);
}
next();
}
app.use(deprecationMiddleware);
Middleware en Python Flask
from datetime import datetime
from flask import Flask, request, g
DEPRECATED_PATHS = {
"/v1/orders": {"sunset": "2026-10-01", "replacement": "/v2/orders"},
"/v1/products": {"sunset": "2026-10-01", "replacement": "/v2/products"},
}
@app.before_request
def add_deprecation_headers():
for path, info in DEPRECATED_PATHS.items():
if request.path.startswith(path):
g.deprecation_sunset = info["sunset"]
g.deprecation_replacement = info["replacement"]
break
@app.after_request
def set_deprecation_headers(response):
if hasattr(g, "deprecation_sunset"):
response.headers["Deprecation"] = "true"
response.headers["Sunset"] = datetime.strptime(
g.deprecation_sunset, "%Y-%m-%d"
).strftime("%a, %d %b %Y 00:00:00 GMT")
response.headers["Link"] = (
'<https://docs.ejemplo.com/api-migration>; rel="deprecation"'
)
return response
Rastreo del Progreso de Migración
Vigila el tráfico en los endpoints deprecados: es la única forma fiable de saber quién no ha migrado, porque nadie lee el email.
Consulta SQL para Tráfico de Deprecación
SELECT
endpoint,
COUNT(*) AS request_count,
COUNT(DISTINCT client_id) AS unique_clients,
MAX(timestamp) AS last_request
FROM api_requests
WHERE endpoint LIKE '/v1/%'
AND timestamp >= NOW() - INTERVAL '7 days'
GROUP BY endpoint
ORDER BY request_count DESC;
Alertas para Consumidores sin Migrar
Configura una alerta cuando un consumidor con tráfico significativo no haya comenzado a migrar:
alert: stale_deprecation_consumer
expr: |
sum by (client_id) (
rate(api_requests_total{endpoint=~"/v1/.*"}[1h])
) > 10
for: 24h
labels:
severity: warning
annotations:
summary: "Cliente {{ $labels.client_id }} aún usa endpoints v1 deprecados"
description: "Este cliente ha hecho >10 req/h a endpoints v1 en las últimas 24h"
Plan de Comunicación
| Canal | Momento | Audiencia | Contenido |
|---|---|---|---|
| Email masivo | T-90 días | Todos los consumidores registrados | Aviso completo de deprecación + enlace a guía |
| Blog post | T-90 días | Público | Anuncio + contexto del cambio |
| Headers en respuesta API | T-90 días | Integraciones activas | Deprecation: true, header Sunset |
| Banner en panel | T-60 días | Usuarios del panel | Banner persistente con fecha límite |
| Email de seguimiento | T-30 días | Consumidores no migrados | Recordatorio + ofrecer horarios de atención |
| Contacto directo | T-14 días | Alto tráfico no migrado | Email o llamada personal del equipo de API |
| Email final | T-7 días | Todos los restantes | ”Retiro de v1 en 7 días” |
| Página de estado | T-0 | Todos | v1 retorna 410 Gone, actualización de estado |
El punto del escalonamiento no es dar la lata: es que cada canal atrapa a un grupo distinto. El email va a quien registró la key. Los headers van al código que te llama. El banner atrapa al humano que entra a depurar. El contacto directo es para el puñado de consumidores que generan suficiente tráfico como para importar pero no han respondido a nada más.
Variantes
| Contexto | Enfoque | Notas |
|---|---|---|
| API Pública | Aviso de 90+ días, blog post, email | La confianza del consumidor depende de plazos predecibles |
| API Interna | Aviso de 30 días, anuncio en Slack | Iteración más rápida, base de consumidores menor |
| Parche de seguridad de emergencia | Aviso de 7 días, contacto directo | La seguridad tiene prioridad sobre la conveniencia |
| API GraphQL | Directiva @deprecated + aviso | Deprecación a nivel de esquema junto con comunicación |
Lo que funciona
- Enviar headers de deprecación en respuestas de API al menos 90 días antes del retiro (
Deprecation: true,Sunset: <fecha>) - Proporcionar un reemplazo funcional antes de eliminar el endpoint antiguo
- Mantener un changelog con todas las deprecaciones y migraciones
- Rastrear el progreso de migración monitoreando el tráfico a endpoints deprecados
- Ofrecer horarios de atención o una guía de migración para cambios complejos
- Usar múltiples canales de comunicación: el email solo no es suficiente
- Registrar el uso de headers de deprecación para saber qué clientes están al tanto
Errores Comunes
- Anunciar deprecación sin un reemplazo: los consumidores no tienen a dónde ir
- Plazos de aviso demasiado cortos: los clientes enterprise necesitan trimestres para planificar cambios
- Cambiar comportamiento silenciosamente sin anunciar deprecación primero
- No rastrear qué consumidores aún usan endpoints deprecados
- Eliminar sin período de gracia: retorna siempre 410 Gone primero
- Enviar un solo email y asumir que todos lo leyeron: usa múltiples canales
- No proporcionar sandbox para que los consumidores prueben el nuevo endpoint
- Extender la fecha de retiro repetidamente: socava la confianza en futuros plazos
- Olvidar actualizar SDKs y librerías cliente junto con el cambio de API
Troubleshooting
- Los consumidores dicen que nunca recibieron el aviso: no leyeron el email. Es lo esperado, y por eso existen los headers, el banner y los recordatorios. Revisa tus logs de requests: si un cliente sigue llamando a v1 en T-30, le toca un recordatorio; en T-14 con tráfico real, le toca una persona.
- La integración de un cliente se rompe antes de la fecha de retiro: normalmente un campo renombrado que se desplegó antes de tiempo o un cliente que parsea respuestas con demasiada rigidez. Compara la respuesta de v1 con lo que documentó el aviso: si el aviso era correcto, la corrección está de su lado y tu guía de migración lo cubre; si no, les debes un aviso actualizado.
- Un consumidor importante no puede migrar a tiempo: concede una extensión por escrito con fecha de expiración, regístrala en el log de deprecación y hazlo la primera línea de tu aviso final. Nunca extiendas el retiro público para todos por acomodar a un solo consumidor: eso enseña al resto a ignorar tus plazos.
- El tráfico a v1 no ha bajado en T-30: probablemente tus headers de deprecación no están llegando a los clientes. Verifícalo con un curl contra un endpoint deprecado: si
Deprecation: trueno aparece en la respuesta, el middleware no está desplegado donde realmente termina el tráfico (load balancer, gateway o una ruta legacy que lo esquiva). - Alguien pide una excepción después del retiro: la respuesta ya está en la sección de excepciones — no existe “una semana más” una vez que 410 Gone empieza a retornar, porque la alternativa es enseñar a cada aviso futuro que tus plazos son negociables.
Ver También
- The Deprecation HTTP Header — borrador IETF: la especificación detrás de los headers
DeprecationySunsetque usa esta plantilla - RFC 8594 — The Sunset HTTP Header Field: la semántica registrada del header
Sunset - Spec de GraphQL — @deprecated: deprecación a nivel de esquema para campos de GraphQL
- Versionado de API de Stripe: cómo una API pública grande maneja cambios de versión fechados y opt-in
- Plantilla de Changelog de API: el registro continuo que acompaña a cada aviso de deprecación
- Plantilla de Gestión del Ciclo de Vida de API: dónde encaja la deprecación en el ciclo de vida completo de la API
Código complementario: recursos de aviso de deprecación de API: la plantilla, el middleware y las consultas de rastreo de esta página.
Preguntas frecuentes
¿Cuánto aviso debo dar?
APIs públicas: 90-180 días. APIs internas: 30-60 días. Cambios relacionados con seguridad: tan rápido como sea posible con contacto directo.
¿Debería soportar ambas versiones indefinidamente?
No. Cada versión que mantienes viva es más código que parchear, más superficie que proteger y más documentación que mantener honesta. Elige una fecha firme de retiro y cúmplela, con excepciones limitadas.
¿Qué código de estado HTTP debería retornar un endpoint deprecado después del retiro?
Retorna 410 Gone: dice 'esto desapareció para siempre' en lugar de 'quizá sea un bug'. Apunta a los consumidores al reemplazo en el body o en un header Link para que no se queden adivinando.
¿Qué pasa si un cliente importante no puede migrar a tiempo?
Ofrece una extensión temporal con una fecha de expiración documentada. Registra la extensión en tu log de deprecación. No extiendas indefinidamente: eso anula el propósito del retiro.
¿Debería retornar advertencias durante el período de deprecación?
Sí. Retorna 299 Miscellaneous Persistent Warning con un mensaje de deprecación en el header Warning. Es una señal suave que no rompe a los clientes pero aparece en los logs.
¿Cómo depreco un campo de GraphQL?
Usa la directiva @deprecated en tu esquema:
type Order {
total: Float @deprecated(reason: "Usar totalAmount en su lugar. Eliminado en 2026-10-01.")
totalAmount: Float
}
Los clientes de GraphQL ven la advertencia directamente en sus resultados de introspección, y por eso la deprecación a nivel de esquema le gana a un aviso para GraphQL.
¿Debería versionar toda la API o solo los endpoints cambiados?
Versiona el endpoint cuando cambia un endpoint; sube la versión completa de la API solo cuando un cambio coordinado afecta a la mayoría de endpoints a la vez. Los saltos de versión completos cuestan a todo el mundo, así que no gastes uno en un rename.
¿Cómo manejo la deprecación en una integración basada en webhooks?
Envía un evento de webhook deprecation.notice a cada endpoint suscrito con el mismo payload que el aviso: qué cambió, la fecha de retiro, el enlace de migración. Después envía eventos de recordatorio en T-30 y T-7, porque los consumidores de webhooks también ignoran el email.
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 Contrato de Microservicios
Una plantilla para definir contratos de servicio y acuerdos de API entre microservicios.
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 Comunicación de Despliegues
Una plantilla para notas de release y actualizaciones de stakeholders durante despliegues de capacidades.
DocPlantilla de Changelog de API
Plantilla para documentar cambios de API incluyendo cambios breaking, nuevas capacidades, deprecaciones y correcciones.
DocPlantilla de Respuesta de Error de API
Una plantilla reutilizable para respuestas de error de API consistentes, informativas y amigables para desarrolladores que reducen el tiempo de depuración.