# API REST

> Novedades de la API REST, de la más reciente a la más antigua.

## 2026-10-25 · `1.0.0`

**API REST 1.0.0.** Versión 1.0.0 del API REST de Filmo.

### Añadido

- `retryAfter` en el problema `429 rate_limited` (REST y MCP): segundos que debes esperar antes de reintentar, con el mismo valor que la cabecera `Retry-After`; `detail` también lo indica.
- Las filas de `GET /planner/services` incluyen `rowKind` (`summary` o `detail`): cada servicio tiene una fila `summary` (sin asignación) y una fila `detail` por cada persona o vehículo asignado, con el mismo `orderServiceId`. Agrupa por `orderServiceId`; que `staffMemberId` sea nulo en la fila de resumen no significa que el servicio esté sin cubrir.
- Cada respuesta correcta (2xx) de todas las operaciones incluye un `example`: datos ficticios y deterministas (dominios de RFC 2606) que cumplen el esquema de respuesta.
- Un ejemplo de respuesta por código de error (los 20 valores de `code`), como `components.examples.Problem_<code>` y referenciado desde las respuestas de error de todas las operaciones, con el `title` y la estructura reales del problema.

### Cambiado

- Las URI de `type` de los errores pasan a ser `https://docs.filmo.io/errors/<code>` (antes eran `https://developers.filmo.io/errors/<code>`). Basa la lógica en `code`, no en la URI.
- Cada respuesta 409 `conflict` incluye ahora su causa en `errors[0].code`: `in_progress`, `lock_timeout` o `invalid_state`. Donde `errors[].code` antes era `conflict` (infracciones de unicidad y líneas de un lote atómico que fallan porque su estado impide la operación), ahora es `invalid_state`; una línea del lote que no existe o tiene una cantidad no válida sigue indicando `not_found` o `validation_error`.
- Los cuerpos de las respuestas correctas son esquemas con nombre y un campo opcional `meta.warnings`; las respuestas de escritura declaran la cabecera `Idempotent-Replay`.
- La documentación se ha trasladado a https://docs.filmo.io; en producción, `/api/v1/docs` redirige allí.
- Los filtros de fecha (`createdOn`, `issueDateBefore`, `returnTo`…) se publican como un único `type: string` con un `pattern` (un día `YYYY-MM-DD` o un instante ISO 8601 con desplazamiento horario), en lugar de un `anyOf` de `date` y `date-time` que algunos generadores de clientes no podían compilar. El servidor acepta exactamente los mismos valores.
- Las respuestas 401 y 403 dejan de declarar las cabeceras `RateLimit-*`: nunca se enviaban, ya que estos errores se responden antes de que la petición cuente para el límite.
- Cada operación que puede responder 402 por faltar un producto adicional lo identifica en la extensión `x-required-addon` (por ejemplo, `["incidence"]`). `ProblemDetails.requiredAddon` y `AccountDto.addons` son ahora enumeraciones cerradas de identificadores de productos adicionales; `GET /account` solo devuelve identificadores de ese catálogo.
- El campo `path` de las entradas de `errors[]` de un 409 `contact_in_use` (el tipo de registro que utiliza el contacto: `orders`, `projects`, `quotes`, `invoices`, `proformas`, `creditNotes`, `simpleCreditNotes`, `salesReceipts`, `supplierInvoices`, `contracts`, `subrents`, `purchaseOrders`, `sepaMandates`, `receipts`, `consignments`), `address_in_use` (siempre `orders`) e `insufficient_stock` (`items` o `spaces`) es un conjunto cerrado, publicado por código en la extensión `x-path-values` de `ProblemDetails.errors[].path`.
- `Idempotency-Key` se declara con `minLength: 1`. Una clave vacía ya producía un 400 `validation_error` en REST; las herramientas MCP ahora rechazan un `idempotencyKey` vacío de la misma forma (`errors[0].path` = `idempotencyKey`), en lugar de ignorarlo y ejecutar la escritura sin protección.

### Corregido

- El resultado de cada herramienta MCP cumple ahora la validación de los SDK oficiales (`Client.callTool` en TypeScript y Python): antes, las respuestas correctas con `meta.idempotencyKey` y todos los errores fallaban con `-32602 Structured content does not match the tool's output schema`.
- Las lecturas de detalle enviadas con `If-None-Match` responden ahora `304 Not Modified` (sin cuerpo y con `ETag`) cuando la etiqueta está vigente, tal como ya declaraba la especificación. Hasta ahora devolvían una respuesta 200 completa.
- Sin `Accept-Language`, los errores 401 de una clave existente (revocada, caducada, con propietario inactivo o sin rol de administrador) y el 403 `insufficient_scope` se devolvían en español, independientemente del idioma preferido por el propietario de la clave. Ahora utilizan el idioma del propietario, como los errores posteriores; las peticiones sin credencial o con una clave desconocida siguen respondiendo en español.
- `upsertExternalInvoice` documentaba los problemas de cliente y totales como 422; son errores 400 `validation_error`, y `errors[0].path` ahora identifica el campo (`contactId`, `contactTaxId`, `contactName`, `subTotal`, `taxTotal`, `total`, `lines[n].taxRate`).

---

URL canónica: https://docs.filmo.io/es/changelog/rest-api  
Última actualización: 2026-10-25