> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nubidoc.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Prestaciones de las citas: API y webhooks

> Sincronizar todas las prestaciones de una cita y modificar su duración sin crear otra cita.

## Consultar todas las prestaciones

La consulta de una cita y los webhooks de citas incluyen la colección `services`. Cada elemento representa una línea de la cita: una misma prestación puede aparecer varias veces, con distintos identificadores de línea.

| Campo | Significado |
| - | - |
| `appointment_services_id` | Identificador de la línea de la cita. |
| `serviceoffer_id` | Identificador de la prestación del catálogo. |
| `name` | Nombre de la prestación. |
| `code` | Código interno de la prestación. |
| `externalcode` | Código externo de la prestación. |
| `randomcode` | Identificador público de la prestación. |

El código de confirmación identifica la cita y es independiente de estos códigos.
Si la cita no tiene prestaciones, `services` es `[]`.
Los códigos sin valor (`code`, `externalcode` y `randomcode`) se representan siempre como `null`.

Ejemplo del campo `data.services` de un webhook:

```json theme={null}
[
  {
    "appointment_services_id": 8101,
    "serviceoffer_id": 42,
    "name": "Consulta inicial",
    "code": "CONS01",
    "externalcode": "EXT-42",
    "randomcode": "consulta-inicial-publica"
  },
  {
    "appointment_services_id": 8102,
    "serviceoffer_id": 42,
    "name": "Consulta inicial",
    "code": "CONS01",
    "externalcode": "EXT-42",
    "randomcode": "consulta-inicial-publica"
  }
]
```

## Recibir cambios mediante webhook

En **Administración → Centro → Integraciones**, configure una integración de citas suscrita al evento de actualización. También recibe los cambios realizados directamente en las líneas de prestaciones, sin tener que guardar de nuevo la cabecera de la cita.

El mensaje contiene la lista completa resultante. El receptor debe sustituir su asociación anterior por esa lista; una lista vacía significa que se han eliminado todas las prestaciones. Los guardados internos de una misma operación se agrupan y una transacción revertida no deja un aviso entregable.

Las suscripciones y los campos anteriores siguen funcionando. Se conserva el mecanismo de entrega y reintentos existente.

## Modificar una cita mediante API

Una integración autorizada puede cambiar la duración y sustituir la lista de prestaciones de una cita existente, conservando su identificador y su código de confirmación.

Utilice `PUT /es/api/v1/booking-apikey/appointment-update/{code}` con el código de confirmación de la cita y la cabecera `X-API-Key`. También se admite `POST`. La clave necesita el permiso explícito `booking:appointments:write` o `booking:*`; las claves antiguas sin permisos definidos no tienen acceso a esta operación.

```http theme={null}
PUT /es/api/v1/booking-apikey/appointment-update/ABC123XYZ
X-API-Key: ndk_clave_de_ejemplo
Content-Type: application/json

{
  "duration": 60,
  "services": [
    {"appointment_services_id": 8101, "serviceoffer_id": 42},
    {"serviceoffer_id": 43}
  ]
}
```

| Campo | Uso |
| - | - |
| `duration` | Entero entre 1 y 1440 minutos. Mantiene la hora de inicio y cambia la de fin. |
| `services` | Lista completa de hasta 100 líneas; cada una requiere `serviceoffer_id` como entero positivo. |
| `appointment_services_id` | Identificador opcional de una línea de esa cita. Incluirlo conserva la línea; omitirlo crea una nueva con cantidad 1. |

Envíe al menos `duration` o `services`. Omitir un campo mantiene su valor actual; `services: []` elimina todas las prestaciones. Cuando se envía una lista, se eliminan las líneas existentes que no figuren en ella. Para conservarlas, envíe sus identificadores y prestaciones. Una prestación puede repetirse en líneas distintas; un identificador de línea no puede repetirse.

`null`, números entre comillas y campos adicionales se rechazan. Los precios y cantidades no se editan mediante esta operación; Nubidoc calcula los importes según sus reglas. Cambiar prestaciones no ajusta automáticamente la duración: indique `duration` cuando proceda.

La respuesta de éxito es HTTP 200 con `success: true` y `data`, que contiene los datos de la cita, incluidos `duration`, `time_end` y la lista completa `services`. Repetir los mismos valores e identificadores no genera otro aviso. Si repite líneas sin identificador, se crearán nuevas identidades de línea; reutilice los identificadores de la respuesta anterior.

La operación comprueba los permisos de la clave, que los datos pertenecen al mismo cliente y que el intervalo completo cabe en la disponibilidad del profesional. Solo admite citas futuras solicitadas o programadas con paciente. Conserva paciente, fecha, hora de inicio, profesional y centro. Las citas facturadas con factura emitida, los cobros protegidos y los cambios de prestaciones en citas vinculadas a bonos se rechazan sin aplicar parcialmente los cambios.

| HTTP | Código | Qué revisar |
| - | - | - |
| 400 | `invalid_update` | Campos, tipos, límites e identificadores repetidos. |
| 403 | `insufficient_permissions` | Permiso explícito de escritura de citas de la clave. |
| 404 | `appointment_not_found` | Código y cliente al que pertenece la cita. |
| 400 | `appointment_not_editable`, `appointment_invoiced`, `appointment_bonus_services_locked` | Estado, fecha, paciente, facturación o bono de la cita. |
| 400 | `appointment_service_not_found`, `serviceoffer_not_allowed`, `serviceoffer_professional_not_allowed` | Línea de cita, catálogo del centro y prestaciones del profesional. |
| 409 | `slot_not_available` | Horario, citas, eventos, festivos y bloqueos temporales. |
| 409 | `slot_hold_lock_timeout`, `appointment_changed` | Volver a consultar antes de reintentar la edición. |
| 400 | `appointment_update_error` | Restricción o fallo de guardado. Revisar el mensaje y consultar soporte si persiste. |
| 400 | `wallet_appointment_frozen` | La cita está cobrada con el monedero y no admite esta edición. |
