*API REST › Referencia de endpoints › Alquileres › Pedidos*

# Devolver líneas de pedido

> Marca el material que vuelve como devuelto: qué línea, cuántas unidades y en qué estado.

> **Envía tu propia Idempotency-Key:** Un reintento sin la misma clave duplica el efecto. Envía tu propia Idempotency-Key y sigue la tabla de reintentos. Con `atomic: false`, un 207 lista las líneas que fallaron: reenvía solo esas, con una clave nueva.

Cuelga del recurso y no de un pedido porque una descarga cruza pedidos, que es lo que esta llamada resuelve de una vez. Envía `Idempotency-Key`: devolver dos veces la misma línea metería el material en el stock dos veces, y cada línea va como máximo una vez por petición (suma sus cantidades). Es un lote: `atomic` es true por defecto, así que una línea que no se puede devolver rechaza todo el lote con 409 y una incidencia por línea fallida, sin tocar nada; con `atomic: false` cada pedido se procesa por separado y la respuesta es 207 con un resultado por elemento, donde los fallidos no se devolvieron y el resto SÍ. Si todo va bien, la respuesta es 200 con un resultado por elemento, en el orden de la petición.

`POST /api/v1/orders/line-items/returns` — permiso `orders:write`

Permiso: `orders:write` · 120/min · Idempotency-Key · Envía tu propia Idempotency-Key · MCP: `filmo_orders_line_items_return`

## Autorizaciones

Clave de API como Bearer, con el permiso de abajo. `orders:write`

## Cabeceras

| Nombre | Tipo | Obligatorio | Descripción |
| --- | --- | --- | --- |
| `Idempotency-Key` | string | No | Identificador único de la petición, elegido por el cliente (sirve un UUID). Entre 1 y 255 caracteres: una cabecera vacía se rechaza con 400 `validation_error`, porque el cliente se creería protegido. Repetir la misma clave con el MISMO cuerpo en 24 h devuelve la respuesta guardada sin volver a ejecutar, con la cabecera `Idempotent-Replay: true`. Con un cuerpo DISTINTO devuelve 422. Es la forma segura de reintentar tras un tiempo de espera de red. |

## Cuerpo

Esquema del cuerpo: `OrderLineItemsReturnBody`

| Nombre | Tipo | Obligatorio | Descripción |
| --- | --- | --- | --- |
| `items` | object[] | Sí | Líneas que se devuelven. Al menos una, como máximo 500, cada línea como máximo una vez. |
| `items.lineItemId` | string | Sí | Línea de pedido que se devuelve. |
| `items.checkInQuantity` | number | Sí | Unidades que se devuelven, al menos una. Puede ser una devolución parcial. |
| `items.returnCondition` | string | Sí | Estado físico en el que vuelve el material: `good`, `damaged`, `lost`, `needs_repair` o `incident`. `good`, `damaged`, `lost`, `needs_repair`, `incident` |
| `checkedInAt` | string<date-time> | No | Fecha efectiva de la devolución, en ISO 8601 con desplazamiento. Por defecto, ahora. |
| `atomic` | boolean | No | Todo o nada (por defecto true): si alguna línea no se puede devolver, no se devuelve ninguna y la respuesta es 409 con una incidencia por línea. Con false, cada pedido se procesa por separado, la respuesta es 207 y cada elemento lleva su propio estado. = `true` |

## Ejemplos de petición

*Devolver líneas de pedido*

**cURL**

```bash
curl https://app.filmo.io/api/v1/orders/line-items/returns \
  --request POST \
  --header "Authorization: Bearer $FILMO_API_KEY" \
  --header "Idempotency-Key: $(uuidgen 2>/dev/null || cat /proc/sys/kernel/random/uuid)" \
  --header 'Content-Type: application/json' \
  --data '{
  "items": [
    {
      "lineItemId": "oli_00913",
      "checkInQuantity": 3,
      "returnCondition": "good"
    },
    {
      "lineItemId": "oli_01120",
      "checkInQuantity": 1,
      "returnCondition": "damaged"
    }
  ],
  "checkedInAt": "2026-09-10T18:30:00+02:00"
}'
```

**Node.js**

```javascript
fetch('https://app.filmo.io/api/v1/orders/line-items/returns', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer YOUR_FILMO_API_KEY',
    'Idempotency-Key': crypto.randomUUID(),
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    items: [
      {
        lineItemId: 'oli_00913',
        checkInQuantity: 3,
        returnCondition: 'good'
      },
      {
        lineItemId: 'oli_01120',
        checkInQuantity: 1,
        returnCondition: 'damaged'
      }
    ],
    checkedInAt: '2026-09-10T18:30:00+02:00'
  })
})
```

**Python**

```python
import uuid
import requests

requests.post(
    "https://app.filmo.io/api/v1/orders/line-items/returns",
    headers={
      "Authorization": "Bearer YOUR_FILMO_API_KEY",
      "Idempotency-Key": str(uuid.uuid4()),
      "Content-Type": "application/json"
    },
    json={
      "items": [
        {
          "lineItemId": "oli_00913",
          "checkInQuantity": 3,
          "returnCondition": "good"
        },
        {
          "lineItemId": "oli_01120",
          "checkInQuantity": 1,
          "returnCondition": "damaged"
        }
      ],
      "checkedInAt": "2026-09-10T18:30:00+02:00"
    }
)
```

## Respuesta

Esquema de la respuesta: `OrderLineReturnResultDto`

| Estado | Descripción |
| --- | --- |
| 200 | Respuesta correcta. |
| 207 | Multi-Status (`atomic: false`): el lote se procesó elemento por elemento; lee cada `status` y `error`. |
| 400 | Petición no válida (validation_error): consulta o cuerpo mal formados. `errors[]` enumera cada campo erróneo con su código estable. |
| 401 | Fallo de autenticación (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin). |
| 403 | No permitido (insufficient_scope: la clave de API no tiene el scope requerido, indicado en `requiredScope`; forbidden: el propietario de la clave carece del permiso que exige la operación). `insufficient_scope` se responde antes de que la petición cuente contra el límite de peticiones, así que no lleva cabeceras `RateLimit-*`; `forbidden` sí. |
| 404 | Recurso no encontrado (not_found): no existe o está fuera del alcance de la clave de API. |
| 409 | Conflicto (conflict): el estado actual del recurso impide la operación, ya hay en curso una petición con esa Idempotency-Key, o otra escritura condicional (`If-Match`) retuvo el recurso durante más de cinco segundos. `errors[0].code` indica cuál: `in_progress` y `lock_timeout` se resuelven reintentando; `invalid_state` no, porque el estado del recurso prohíbe la operación. |
| 422 | Idempotency-Key reutilizada (idempotency_key_reused): la misma clave se usó antes con un cuerpo distinto. Cambia la clave. |
| 429 | Límite de peticiones superado (rate_limited): reintenta tras `Retry-After` segundos; `RateLimit-*` indica qué cuota se ha agotado. |
| 500 | Error interno (internal_error). |

**200**

| Nombre | Tipo | Descripción |
| --- | --- | --- |
| `data` | object[] |  |
| `data.index` | integer | Posición del elemento en el array de la petición. |
| `data.id` | string | Identificador del elemento tal como se envió. |
| `data.status` | string | `returned` o `failed`. `returned`, `failed` |
| `data.error` | object | Por qué falló; null cuando es `returned`. |
| `data.error.code` | string | Código de error estable del elemento, del mismo catálogo que `errors[]`. |
| `data.error.message` | string | Motivo localizado. |
| `meta` | object | Información adicional sobre la respuesta. |
| `meta.warnings` | object[] | Avisos del ciclo de vida; solo aparecen cuando la operación está obsoleta. |
| `meta.warnings.code` | string | Código de aviso estable. `deprecated` |
| `meta.warnings.message` | string | Para personas: qué está obsoleto, hasta cuándo y qué usar. |
| `meta.warnings.sunset` | string | Día (YYYY-MM-DD) en que la operación deja de estar disponible. |
| `meta.warnings.replacement` | string | `operationId` de la operación que hay que usar en su lugar, o null si no hay ninguna. |
| `meta.warnings.link` | string | Dónde está documentada la deprecación (el changelog). |

*Respuesta de ejemplo · 200*

```json
{
  "data": [
    {
      "index": 1,
      "id": "order_line_return_result_9f3a2b",
      "status": "returned",
      "error": {
        "code": "Example code",
        "message": "Example text."
      }
    }
  ]
}
```

**207**

| Nombre | Tipo | Descripción |
| --- | --- | --- |
| `data` | object[] |  |
| `data.index` | integer | Posición del elemento en el array de la petición. |
| `data.id` | string | Identificador del elemento tal como se envió. |
| `data.status` | string | `returned` o `failed`. `returned`, `failed` |
| `data.error` | object | Por qué falló; null cuando es `returned`. |
| `data.error.code` | string | Código de error estable del elemento, del mismo catálogo que `errors[]`. |
| `data.error.message` | string | Motivo localizado. |
| `meta` | object | Información adicional sobre la respuesta. |
| `meta.warnings` | object[] | Avisos del ciclo de vida; solo aparecen cuando la operación está obsoleta. |
| `meta.warnings.code` | string | Código de aviso estable. `deprecated` |
| `meta.warnings.message` | string | Para personas: qué está obsoleto, hasta cuándo y qué usar. |
| `meta.warnings.sunset` | string | Día (YYYY-MM-DD) en que la operación deja de estar disponible. |
| `meta.warnings.replacement` | string | `operationId` de la operación que hay que usar en su lugar, o null si no hay ninguna. |
| `meta.warnings.link` | string | Dónde está documentada la deprecación (el changelog). |

*Respuesta de ejemplo · 207*

```json
{
  "data": [
    {
      "index": 1,
      "id": "order_line_return_result_9f3a2b",
      "status": "returned",
      "error": {
        "code": "Example code",
        "message": "Example text."
      }
    }
  ]
}
```

## Errores

| Estado | Códigos | Significado |
| --- | --- | --- |
| 400 | `validation_error` | Consulta o cuerpo mal formados. `errors[]` enumera cada campo erróneo con su código estable. |
| 404 | `not_found` | No existe o queda fuera del alcance de la clave de API. |
| 409 | `conflict` | El estado actual del recurso impide la operación, ya hay en curso una petición con esa Idempotency-Key, u otra escritura condicional (`If-Match`) retuvo el recurso durante más de cinco segundos. `errors[0].code` indica cuál: `in_progress` y `lock_timeout` se resuelven reintentando; `invalid_state` no, porque el estado del recurso prohíbe la operación. |
| 422 | `idempotency_key_reused` | La misma clave se usó antes con un cuerpo distinto. Cambia la clave. |

## Obsolescencia

Esta operación no está obsoleta. Las obsolescencias se anuncian con la cabecera Deprecation y una fecha de retirada.

---

URL canónica: https://docs.filmo.io/es/rest-api/endpoint-reference/orders/return-order-lines  
Última actualización: 2026-10-25