Skip to content

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

CampoTipoDescripción
booking_link_idstringLiga origen.
user_idstringHost de la cita.
event_idstringEvento creado en el calendario del host. null si la reserva fue cancelada.
lead_idstringLead generado en Prospección. null si la liga tiene create_lead: false.
starts_at / ends_atstringISO 8601 UTC.
timezonestringIANA tz de la liga al momento de agendar.
name / emailstringDatos del booker.
responsesobjectRespuestas a los custom_fields de la liga, keyed por key.
statusenumconfirmed, cancelled.
cancelled_at / cancellation_reasonstringSolo presentes cuando status = "cancelled".

Listar reservas

GET/api/v1/calendar/bookingsread-bookings

Query params: limit, starting_after, ending_before, include_total, page (ver Paginación).

Filtros adicionales:

ParamDescripción
booking_link_idLimita a reservas de una liga específica.
user_idLimita a reservas de un host específico.
statusconfirmed o cancelled.
fromISO 8601. Reservas con starts_at >= from.
toISO 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-bookings

Crear 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_bookings del host).
  • Los custom_fields marcados como required: true deben venir poblados en responses.

Campos aceptados en data:

CampoTipoNotas
booking_link_idstringRequerido. La liga debe estar activa y pertenecer al workspace.
starts_atstringRequerido. ISO 8601. La duración la define la liga.
namestringRequerido.
emailstringRequerido. Formato email válido.
responsesobjectMap 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-bookings

Cambia 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

errorHTTPCuándo
invalid_booking_link422booking_link_id ausente, la liga no existe en este workspace, o está inactiva.
slot_unavailable409El starts_at solicitado ya no está disponible (cae fuera de la availability o colisiona).
invalid_submission422Campos requeridos vacíos, email mal formado, custom_fields requeridos sin valor.
validation_failed422Mongoid rechazó el documento (raro: indica payload mal armado).

Hecho con cuidado por Finova.