Appearance
Reservas
Una reserva (Booking) representa una cita confirmada agendada a través de una liga de agenda. Cada reserva crea automáticamente:
- Un evento en el calendario del host (con sync a Google si está conectado).
- Un lead en Prospección (si la liga tiene
create_lead: true).
Puedes usar este API para listar reservas existentes, crearlas programáticamente (saltándote la landing pública) o cancelarlas.
El objeto Booking
json
{
"id": "65c2d3e4f5a6b7c8d9e012f3",
"booking_link_id": "65b1c2d3e4f5a6b7c8d9e012",
"user_id": "64f1a2b3c4d5e6f701234567",
"event_id": "65c2d3e4f5a6b7c8d9e01234",
"lead_id": "65c2d3e4f5a6b7c8d9e01235",
"starts_at": "2026-05-20T17:00:00Z",
"ends_at": "2026-05-20T17:30:00Z",
"timezone": "America/Mexico_City",
"name": "Laura Méndez",
"email": "laura@example.com",
"responses": {
"empresa": "Acme SA de CV",
"interes": "Quiero ver el módulo de inventario"
},
"status": "confirmed",
"cancelled_at": null,
"cancellation_reason": null,
"created_at": "2026-05-15T10:00:00Z",
"updated_at": "2026-05-15T10:00:00Z"
}Campos
| Campo | Tipo | Descripción |
|---|---|---|
booking_link_id | string | Liga origen. |
user_id | string | Host de la cita. |
event_id | string | Evento creado en el calendario del host. null si la reserva fue cancelada. |
lead_id | string | Lead generado en Prospección. null si la liga tiene create_lead: false. |
starts_at / ends_at | string | ISO 8601 UTC. |
timezone | string | IANA tz de la liga al momento de agendar. |
name / email | string | Datos del booker. |
responses | object | Respuestas a los custom_fields de la liga, keyed por key. |
status | enum | confirmed, cancelled. |
cancelled_at / cancellation_reason | string | Solo presentes cuando status = "cancelled". |
Listar reservas
GET
/api/v1/calendar/bookingsread-bookingsQuery params: limit, starting_after, ending_before, include_total, page (ver Paginación).
Filtros adicionales:
| Param | Descripción |
|---|---|
booking_link_id | Limita a reservas de una liga específica. |
user_id | Limita a reservas de un host específico. |
status | confirmed o cancelled. |
from | ISO 8601. Reservas con starts_at >= from. |
to | ISO 8601. Reservas con starts_at <= to. |
Performance
La query se apoya en { company_id: 1, created_at: -1 } para paginación por cursor y en { company_id: 1, status: 1, starts_at: 1 } cuando filtras por estado + rango temporal. Para volúmenes altos prefiere starting_after sobre page.
Obtener una reserva
GET
/api/v1/calendar/bookings/:idread-bookingsCrear una reserva programáticamente
POST
/api/v1/calendar/bookingscreate-bookingsÚtil cuando ya tienes el contacto en otro sistema y quieres agendar sin pasar por la landing pública. La reserva sigue las mismas reglas de validación que la landing:
- El slot debe caer dentro de la availability de la liga.
- No puede colisionar con otras reservas, eventos del host ni Google FreeBusy (sujeto al setting
block_overlapping_bookingsdel host). - Los
custom_fieldsmarcados comorequired: truedeben venir poblados enresponses.
Campos aceptados en data:
| Campo | Tipo | Notas |
|---|---|---|
booking_link_id | string | Requerido. La liga debe estar activa y pertenecer al workspace. |
starts_at | string | Requerido. ISO 8601. La duración la define la liga. |
name | string | Requerido. |
email | string | Requerido. Formato email válido. |
responses | object | Map de { campo_key: valor }. Para checkboxes, manda true/false. |
bash
curl -X POST https://developers.fi-nova.com/api/v1/calendar/bookings \
-H 'Authorization: Bearer finova_sk_TU_SECRETO' \
-H 'Content-Type: application/json' \
-d '{
"data": {
"booking_link_id": "65b1c2d3e4f5a6b7c8d9e012",
"starts_at": "2026-05-20T17:00:00Z",
"name": "Laura Méndez",
"email": "laura@example.com",
"responses": {
"empresa": "Acme SA de CV",
"newsletter": true
}
}
}'javascript
await fetch('https://developers.fi-nova.com/api/v1/calendar/bookings', {
method: 'POST',
headers: {
Authorization: 'Bearer finova_sk_TU_SECRETO',
'Content-Type': 'application/json',
},
body: JSON.stringify({
data: {
booking_link_id: '65b1c2d3e4f5a6b7c8d9e012',
starts_at: '2026-05-20T17:00:00Z',
name: 'Laura Méndez',
email: 'laura@example.com',
responses: {
empresa: 'Acme SA de CV',
newsletter: true,
},
},
}),
});Idempotency-Key recomendado
Igual que con Leads, si tu integración puede generar reintentos (webhook, double-submit), manda un Idempotency-Key derivado de algo estable (ej. link_id + email + starts_at) para evitar reservas duplicadas.
Cancelar una reserva
DELETE
/api/v1/calendar/bookings/:iddelete-bookingsCambia el status a cancelled, borra el evento del calendario del host (incluido Google si está sincronizado) y devuelve la reserva final con cancelled_at poblado.
Query param opcional: cancellation_reason.
bash
curl -X DELETE 'https://developers.fi-nova.com/api/v1/calendar/bookings/65c2d3e4f5a6b7c8d9e012f3?cancellation_reason=cliente%20no%20pudo%20asistir' \
-H 'Authorization: Bearer finova_sk_TU_SECRETO'Respuesta 200 OK con el booking actualizado (a diferencia de otros recursos que devuelven 204 No Content, aquí devolvemos el objeto para que veas el cancelled_at y propaguen al estado de tu lado).
Errores específicos
error | HTTP | Cuándo |
|---|---|---|
invalid_booking_link | 422 | booking_link_id ausente, la liga no existe en este workspace, o está inactiva. |
slot_unavailable | 409 | El starts_at solicitado ya no está disponible (cae fuera de la availability o colisiona). |
invalid_submission | 422 | Campos requeridos vacíos, email mal formado, custom_fields requeridos sin valor. |
validation_failed | 422 | Mongoid rechazó el documento (raro: indica payload mal armado). |