Referencia · Reservas
Crear una reserva de uno a ocho turnos
POST /api/v1/reservas
Ver en MarkdownPOST/api/v1/reservas
Scope reservas:crear. Exige Idempotency-Key: misma clave y mismo cuerpo devuelven la misma reserva (200, operacion.repetida: true); otro cuerpo con la misma clave da 409 CONFLICTO_INTENCION. Con seña, la reserva queda GUARDADO con pago: PENDIENTE y datos.sena.checkoutUrl (Mercado Pago); se confirma solo por el webhook de MP.
Autenticación: Authorization: Bearer <clave>. Ver Autenticación.
Parámetros
| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
Idempotency-Key | header | string | Sí | Formato ^[A-Za-z0-9._:-]{8,100}$. |
Cuerpo
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
turnos | array de object | Sí | Entre 1 y 8 elementos. |
turnos[].servicioId | string | Sí | |
turnos[].varianteId | string o null | No | |
turnos[].profesionalId | string o null | No | |
turnos[].fecha | string (date) | Sí | |
turnos[].hora | string | Sí | Hora del negocio. Formato ^(?:[01]\d|2[0-3]):[0-5]\d$. |
turnos[].addOnIds | array de string | No | Entre 0 y 50 elementos. |
sucursalId | string o null | No | |
modoCadena | "uno_tras_otro" | No | |
cliente | object | Sí | |
cliente.nombre | string | Sí | Hasta 120 caracteres. |
cliente.telefono | string | Sí | Hasta 32 caracteres. |
cliente.codigoPais | string | No | Hasta 6 caracteres. Por defecto +54. |
cliente.email | string | No | Hasta 254 caracteres. |
cliente.consintioContacto | boolean | No | |
notas | string | No | Hasta 4000 caracteres. |
cuponCodigo | string | No | Hasta 64 caracteres. |
Ejemplo
curl -X POST "https://turnovapp.com/api/v1/reservas" \
-H "Authorization: Bearer $TURNOVA_CLAVE_SECRETA" \
-H "Idempotency-Key: reserva-7f3c2a9e-01" \
-H "Content-Type: application/json" \
-d '{ "turnos": [ { "servicioId": "cmh3s0abc0012", "fecha": "2030-01-10", "hora": "10:00" } ], "cliente": { "nombre": "Ana Pérez", "telefono": "+5493515550101", "email": "[email protected]" } }'Respuestas
| HTTP | Qué significa |
|---|---|
| 200 | Reintento de una reserva ya hecha con la misma clave |
| 201 | Reserva nueva |
| 400 | Datos inválidos: mirá error.campos (ENTRADA_INVALIDA, IDEMPOTENCY_KEY_FALTANTE…). |
| 401 | Clave faltante, inválida o revocada. |
| 403 | Origen no permitido, permiso faltante, clave secreta desde un navegador o plan sin la API (PLAN_SIN_API). |
| 404 | No existe o no es de este negocio. |
| 409 | Conflicto: el horario ya no está libre, otra intención con la misma Idempotency-Key o el servicio se reserva por WhatsApp. |
| 429 | Demasiados pedidos (LIMITE_USO): esperá Retry-After segundos. |
| 500 | Error técnico: reintentá con los mismos datos (y la misma Idempotency-Key). |
Respuesta 201
{
"version": 1,
"ok": true,
"progreso": {
"principal": "GUARDADO",
"pago": "PENDIENTE"
},
"operacion": {
"referencia": "cmh4k2n9x0001",
"repetida": false
},
"requiereRevision": false,
"datos": {
"compraId": "cmh4k2n9x0001",
"total": 25000,
"sena": {
"monto": 6250,
"checkoutUrl": "https://www.mercadopago.com.ar/checkout/v1/redirect?pref_id=123456-abcd"
},
"turnos": [
{
"turnoId": "cmh4k2pa10003",
"servicio": "Masaje descontracturante",
"profesional": "Lucía",
"fecha": "2030-01-10",
"hora": "10:00",
"duracionMin": 60,
"extras": [],
"sesionesTotal": null
}
]
}
}| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
datos.compraId | string | No | |
datos.total | number | No | |
datos.sena | object o null | No | |
datos.sena.monto | number | No | |
datos.sena.checkoutUrl | string o null | No | Link de Mercado Pago. MP vuelve a la página de resultado de Turnova. |
datos.turnos | array de object | No | |
datos.turnos[].turnoId | string | No | |
datos.turnos[].servicio | string | No | |
datos.turnos[].profesional | string | No | |
datos.turnos[].fecha | string (date) | No | |
datos.turnos[].hora | string | No | |
datos.turnos[].duracionMin | integer | No | |
datos.turnos[].extras | array de string | No | |
datos.turnos[].sesionesTotal | integer o null | No |
Los errores siguen el formato común: ver Errores.