Changelog y compatibilidad
Qué te podemos cambiar sin avisarte, qué no, y qué cambió hasta hoy. Incluida la ruptura que hubo, contada con lo que sí y lo que no se rompió.
Lo que /v1 promete
Mientras v1 esté vigente:
| Se puede agregar | Campos nuevos en una respuesta · parámetros opcionales · endpoints nuevos · valores nuevos en un enum de salida |
| No se puede | Quitar ni renombrar un campo · cambiarle el tipo o la semántica · volver obligatorio algo opcional · cambiar un código de estado |
Y la contrapartida es tuya: un cliente tiene que tolerar campos que no conoce. Ése es el contrato. Si tu deserializador falla ante una clave que no esperaba, vas a romperte con un cambio que nosotros tenemos derecho a hacer.
En la práctica, dos reglas para tu cliente:
- No uses parseo estricto que rechace campos desconocidos.
- Ramificá por
errorCode, no pormessage. El código es estable; el texto puede mejorarse. Ver todos los errores.
Cómo se depreca una versión
Si alguna vez sale v2 y v1 se discontinúa:
- Las respuestas de
v1empiezan a llevarDeprecationySunset(RFC 8594), con la fecha a partir de la cual deja de responder. - El anuncio va con al menos seis meses de anticipación.
Hoy v1 está vigente y no se manda ninguna de las dos cabeceras. Medido: se
listaron todas las cabeceras de una respuesta de /v1 y de /openapi.json, y no
aparece ni Deprecation ni Sunset.
Que estén ausentes es deliberado. Mandar un Sunset "por las dudas" te diría que
migres cuando no hay a dónde.
Qué mirar en tu cliente
Loguear la presencia de esas dos cabeceras cuesta una línea y es la forma de enterarte sin leer un blog. Si algún día aparecen, tenés seis meses.
El changelog
2026-07-27 · El prefijo de las API keys pasa de fya_ a emi_
El producto se llamaba FacturaYa y pasó a llamarse Emissa. Con eso:
- Las claves nuevas nacen
emi_test_…/emi_live_…. - La cabecera de modo en las respuestas pasó de
X-Facturaya-ModeaX-Emissa-Mode.
Y lo que NO pasó, que es la parte que importa: ninguna clave dejó de funcionar.
La autenticación resuelve por hash del secreto completo, no por el prefijo. El
prefijo es metadato de presentación: no participa de validar nada. Así que el renombre
no invalidó ninguna credencial, no hubo migración de datos, y las claves fya_
siguen autenticando sin plazo de vencimiento.
Está protegido por una prueba de regresión, y la prueba está verificada por mutación: poniendo la "validación razonable" que alguien podría agregar —
if (!rawKey.startsWith('emi_')) return null;
— el caso falla enseguida:
● validate › una key con el prefijo HEREDADO sigue autenticando
expect(received).not.toBeNull()
Received: null
Sin esa prueba, ese if de una línea desconectaría en silencio a todo integrador que
no haya rotado su clave, y el resto de la suite seguiría en verde.
Lo que sí se rompió, y conviene decirlo: si tu código validaba el formato de la
clave con un ^fya_, o leía la cabecera X-Facturaya-Mode, eso dejó de funcionar. El
renombre de una cabecera de respuesta es exactamente lo que la política de arriba
prohíbe hacer sin aviso.
2026-07-26 · Las API keys se mandan en X-API-Key
Antes viajaban en Authorization: Bearer <key>. Ahora van en su propia cabecera.
Es una ruptura del lado del pedido, y es la de mayor impacto de las dos. Lo que la
hace tolerable es que no falla en silencio: el camino viejo devuelve un 401 que dice
exactamente qué hacer.
{
"statusCode": 401,
"errorCode": "API_KEY_WRONG_HEADER",
"message": "Las API keys van en el header X-API-Key, no en Authorization. Usá: X-API-Key: emi_...",
"details": "La key llego en Authorization; va en X-API-Key desde la version 1"
}
Esa respuesta está medida. No es un "token inválido" genérico: nombra la cabecera correcta.
Por qué esas dos rupturas fueron posibles
Porque ocurrieron antes del primer cliente. No hay nada más honesto que decirlo así: en julio de 2026 no había un solo integrador externo, así que el costo de romper era cero y el beneficio —un contrato coherente con el nombre del producto y una cabecera de autenticación que no se confunde con un JWT— era permanente.
Bajo la política que rige ahora, ninguna de las dos sería admisible sin seis meses de aviso. Renombrar una cabecera de respuesta y cambiar dónde viaja la credencial están las dos en la columna de "no se puede".
Un changelog que arranca vacío es un changelog en el que no se confía: o el producto no cambió nunca, o los cambios no se anotaron. Estos dos están acá porque pasaron.
Lo que no está versionado, y por qué
No todo el backend es /v1:
| Superficie | ¿Versionada? | Para quién |
|---|---|---|
/v1/* | Sí, con esta política | Tu integración |
/health, /ready, /metrics | No | Operación del servicio |
/openapi.json | No | Descubrimiento: lo lee quien todavía no sabe qué versión usar |
| La superficie interna del panel | No, y sin promesas | El panel. No la uses |
La última es la que importa: hay endpoints que el panel usa y que no tienen política de compatibilidad. No están en la referencia a propósito. Si encontrás uno, no lo integres: puede cambiar sin aviso porque nadie prometió lo contrario.
Qué sigue
- Todos los errores — ramificá por
errorCode, no por texto. - La referencia — el contrato de
/v1, generado desde el código.