Skip to navigation

Citas y reservas

Citas es el producto de reservas de Recurrente: citas con tu equipo, clases con cupo, estadías por noche, tarjetas de regalo y contratos. Todo lo que un negocio hace con Citas en el panel también se puede hacer con la API, el CLI recurrente y el servidor MCP.

A diferencia de la mayoría de APIs de reservas, el dinero está en la cita: cuánto cuesta, cuánto pagó el cliente, cuánto falta y el checkout donde paga. No tienes que conciliar una cita con un pago por tu cuenta.

Citas está en toda cuenta de negocio. Una cuenta personal no lo tiene: todos sus endpoints le responden 403 con code: bookings_not_enabled.

Conceptos

ObjetoPrefijoQué es
Serviciosvc_Lo que hace reservable a un producto: duración, quién lo atiende, qué ocupa y qué deja el cliente para apartar la hora. Viaja en el producto como booking.
Profesionalstf_Una persona con quien se reserva, con su horario semanal y sus ausencias.
Recursores_Lo que ocupa una cita además de una persona: una silla, un cuarto, un equipo, una habitación.
Citabk_La hora que aparta un cliente: una cita, un lugar en una clase o una estadía.
Serieser_Una cita que el negocio repite (“cada 2 semanas, 10 veces”).
Sesión de clasecls_Una fecha de una clase, con su cupo.

Un servicio tiene un kind: appointment (un cliente, un profesional), class (varios clientes en una sesión) o lodging (noches en vez de minutos).

Reservar en tres llamadas

1. Consulta los horarios libres. GET /availability responde los mismos horarios que muestra la página pública de citas: resta lo ya reservado, el tiempo extra después de cada cita, la anticipación mínima y el límite diario de la cuenta.

curl "https://app.recurrente.com/api/availability?service_id=svc_ab12cd34&from=2026-10-07&to=2026-10-08" \
-H "X-SECRET-KEY: sk_live_..."
[
{ "starts_at": "2026-10-07T09:00:00-06:00", "ends_at": "2026-10-07T10:00:00-06:00",
"staff_member_id": "stf_ab12cd34", "resource_id": null, "class_session_id": null, "seats_left": null }
]

Una fecha sin hora (2026-10-07) es la medianoche en la zona horaria del negocio. Hasta 31 días por consulta.

2. Reserva uno. Envía el starts_at que te ofrecieron e identifica al cliente con customer_id, o con customer[phone] y customer[name] para crearlo. Usa un Idempotency-Key distinto por cita.

curl -X POST https://app.recurrente.com/api/bookings \
-H "X-SECRET-KEY: sk_live_..." -H "Idempotency-Key: cita-7781" \
-H "Content-Type: application/json" \
-d '{"service_id":"svc_ab12cd34","starts_at":"2026-10-07T09:00:00-06:00",
"customer":{"name":"Lucía Pérez","phone":"+50255551234"}}'

3. Escucha el resultado. La política de pago del servicio decide qué pasa:

PolíticaEstado al reservarQué hace el cliente
noneconfirmed (o pending si el negocio acepta cada cita a mano)Nada.
card_on_filepending con checkout_urlDeja una tarjeta para el cargo por inasistencia; la cita se confirma al dejarla.
depositpending con checkout_urlPaga el anticipo; la cita se confirma al pagarlo.
fullpending con checkout_urlPaga el total.

Una cita pending aparta la hora hasta hold_expires_at. Si nadie paga, la cancela system. Suscríbete a booking.confirm en vez de consultar una y otra vez.

Si alguien tomó la hora antes, la respuesta es 422 con code: slot_taken; vuelve a consultar los horarios.

El dinero de una cita

CampoQué significa
total_in_centsLo que cuesta la cita, congelado al reservar.
paid_in_centsLo que el cliente ya pagó (anticipo, prepago, protección, saldo).
balance_in_centsLo que falta cobrar el día de la cita. 0 en una sesión de paquete o un saldo cobrado fuera de Recurrente.
checkout_urlDonde el cliente paga lo que pide la política, o deja su tarjeta.
balance_checkout_urlEl link de pago del saldo, una vez lo pides.
no_show_fee_checkout_idEl checkout del cargo por inasistencia, cobrado o rechazado.

Cambiar una cita

Cada cambio responde la cita como queda, y todos son idempotentes con un Idempotency-Key.

OperaciónEndpointNotas
MoverlaPOST /bookings/{booking_id}/rescheduleCon el mismo profesional. La respuesta es la cita nueva; rescheduled_from_id apunta a la anterior, que queda cancelada por system. Lo pagado se mueve con ella.
¿A qué hora se puede mover?GET /availability?booking_id=…Su propia hora cuenta como libre.
CancelarlaPOST /bookings/{booking_id}/cancellationEl negocio siempre puede cancelar. No devuelve nada.
Cancelar y devolver, o devolver una canceladaPOST /bookings/{booking_id}/refundDevuelve lo que cobró la cita por los mismos pagos por los que entró. Mueve dinero.
Aceptar o rechazarPOST /bookings/{booking_id}/acceptance, /declinationPara negocios que revisan cada cita. Rechazar devuelve el pago de una cita prepagada.
CompletarlaPOST /bookings/{booking_id}/completionCuando ya llegó su hora.
Marcar inasistenciaPOST /bookings/{booking_id}/no_showNo cobra nada por sí misma.
Cobrar la inasistenciaPOST /bookings/{booking_id}/no_show_feeA la tarjeta que dejó el cliente. Nunca es automático. Un rechazo responde code: declined. Mueve dinero.
Cobrar el saldoPOST /bookings/{booking_id}/balance_chargeCrea (o reutiliza) el link de pago del saldo. No le cobra a nadie.
Saldo pagado afueraPOST /bookings/{booking_id}/outside_paymentEl negocio lo cobró en efectivo o en su propia terminal. Mueve dinero.
Nota sobre el clientePOST /bookings/{booking_id}/customer_notesAparece también en sus próximas citas.

Las operaciones que mueven dinero necesitan una llave con movimiento de dinero habilitado; si no, responden 403 con code: money_movement_not_enabled.

Encontrar una cita por el cliente

GET /bookings filtra por status, un rango from/to sobre la hora de inicio, staff_member_id, customer_id, class_session_id y q, palabras del nombre, correo o teléfono del cliente:

curl "https://app.recurrente.com/api/bookings?q=Ana&from=2026-10-06T00:00:00-06:00&to=2026-10-07T00:00:00-06:00" \
-H "X-SECRET-KEY: sk_live_..."

Citas que se repiten

POST /booking_series reserva al mismo cliente, servicio y profesional cada interval frequency (day, week, month, year, o back_to_back el mismo día), occurrences veces o hasta ends_on. Una hora ocupada o cerrada se salta y aparece en skipped_starts_at en vez de detener la serie. Cada visita se cobra el día de la cita.

Configura tus servicios y tu equipo

Un servicio es un producto con un objeto booking. Envíalo al crear o actualizar el producto (POST /products, PATCH /products/{id}) con los mismos ajustes del formulario del panel: kind, duration_minutes, buffer_after_minutes, payment_policy (y el anticipo o el cargo por inasistencia en centavos), staff_member_ids, resource_ids, extras y, para habitaciones, tarifas por noche. GET /services lista todos los productos que se reservan con el service_id que piden los demás endpoints.

QuéEndpoints
ProfesionalesGET/POST /staff_members, GET/PATCH/DELETE /staff_members/{id} (position los ordena)
La semana y las ausencias de un profesionalGET/PUT /staff_members/{staff_member_id}/schedule, GET/POST/DELETE …/availability_exceptions
Recursos (sillas, cuartos, equipos)GET/POST /resources, GET/PATCH/DELETE /resources/{id}, y los calendarios externos de una habitación en …/ical_feeds
Horario del negocio y fechas especialesGET/PUT /business_hours, GET/POST/DELETE /business_hours/availability_exceptions (closed, u hours para un día corto)

Todo lo que cambias aquí lo lee GET /availability de inmediato. Conectar el Google Calendar de un profesional es un permiso de OAuth y se queda en el panel.

Clases

Una clase es un servicio con kind: class y un capacity. POST /class_sessions escribe sus sesiones con una regla semanal (“martes y jueves a las 5:45 pm, del 6 de octubre al 15 de diciembre”): service_id, staff_member_id, weekdays (0 es domingo), time y el rango de fechas. Es todo o nada: si el instructor o el salón ya están ocupados en alguna de esas horas, no escribe ninguna (busy).

Un lugar es una cita: POST /bookings con class_session_id. Si la clase está llena, la respuesta es 422 con code: full. GET /class_sessions y GET /class_sessions/{id} muestran los lugares tomados y libres.

POST /class_sessions/{class_session_id}/cancellation cancela una sesión: cada lugar se cancela como el negocio y se devuelve (una sesión de paquete vuelve a su paquete), y cada cliente recibe el aviso. Mueve dinero.

Lista de espera

POST /waitlist_entries pone a un cliente en la lista de espera de un servicio para hasta cinco días, cada uno entero o una parte (morning, afternoon, evening), como el “Avísame” de la página pública. Cuando se cancela o se mueve una cita que le sirve, recibe un WhatsApp con el link para reservarla. GET /waitlist_entries lista quién espera; DELETE /waitlist_entries/{id} quita a alguien.

Alojamiento

Un tipo de habitación es un servicio con kind: lodging; cada habitación física es un recurso. Las estadías también son citas, con un objeto stay (tipo, habitación, fechas de llegada y salida, noches, huéspedes, la cuenta abierta y el registro de huéspedes).

  1. GET /lodging/availability?check_in_on=…&check_out_on=…&guests=2 responde cada tipo de habitación con sus habitaciones libres y el precio de la estadía noche por noche, como lo calcula la página pública (temporadas, descuento por estadía larga, huéspedes extra, impuesto de hospedaje).
  2. POST /stays la reserva con room_type_id, las fechas y el huésped. La política de pago funciona igual que en las citas.
  3. El día de la llegada: POST /stays/{stay_id}/check_in (abre una cuenta para los extras), …/guest_registration (el registro de huéspedes), …/date_change, …/unit_assignment, y POST /stays/{stay_id}/check_out. El check-out cierra la cuenta según channel: payment_link (por defecto), pos, o saved_card, que cobra la tarjeta y mueve dinero.

Las operaciones de citas de arriba (link del saldo, pagado afuera, inasistencia, cargo por inasistencia, cancelar, devolver) también funcionan con estadías. GET /bookings?kind=stay las lista, POST/DELETE /maintenance_blocks saca una habitación de venta unas noches y GET /lodging/occupancy da la ocupación y los ingresos del mes.

Tarjetas de regalo

OperaciónEndpointNotas
Vender o recargarPOST /gift_cardsAbre el checkout que vende una tarjeta (o recarga gift_card_id). No le cobra a nadie por sí mismo: la tarjeta se emite al pagarse.
Listar, leerGET /gift_cards, GET /gift_cards/{id}Con el saldo y cada movimiento. q busca por código, o por nombre o correo de quien la recibe.
CanjearPOST /gift_cards/{gift_card_id}/redemptionGasta saldo por una venta cobrada fuera de un checkout de Recurrente. Mueve dinero.
AjustarPOST /gift_cards/{gift_card_id}/adjustmentcredit o debit, con una nota. Mueve dinero.
AnularPOST /gift_cards/{gift_card_id}/voidLa tarjeta deja de funcionar y pierde su saldo. Mueve dinero.
ConfiguraciónGET/PATCH /gift_card_settingsSi el negocio vende tarjetas de regalo y cuántos meses dura una tarjeta.

El código funciona como efectivo: quien lo tiene lo gasta. Mantenlo fuera de tus logs. Los clientes canjean códigos en su propio checkout; eso se queda en el checkout.

Contratos

OperaciónEndpointNotas
PlantillasGET/POST /contract_templates, GET/PATCH/DELETE /contract_templates/{id}body es HTML con variables ({nombre}, {servicio}, {fecha}…); fields son los datos que llena el cliente; service_ids la envía con cada cita de esos servicios.
Borrador con IAPOST /contract_template_draftsDescribe qué debe aceptar el cliente; la respuesta es una plantilla sin guardar para revisar. 20 por hora.
EnviarPOST /contractsPor WhatsApp y correo, con recordatorio a las 48 horas. charge_amount_in_cents pide firmar antes de pagar.
Enviar los contratos de una citaPOST /bookings/{booking_id}/contract_deliveryLos que piden sus servicios y aún no se enviaron.
SeguimientoGET /contracts, GET /contracts/{id}, POST /contracts/{contract_id}/remindersigning_url es la página donde firma el cliente.
PDF firmadoGET /contracts/{contract_id}/pdf409 pdf_not_ready hasta que esté firmado.

La firma siempre ocurre en la página del cliente.

Configuración, paquetes y notas

QuéEndpoints
Activar o desactivar una forma de vender (store, citas, lodging, gift_cards, contracts)GET /sales_channels, PUT /sales_channels/{key} con {"on": false}
Políticas (anticipación, ventana, cancelaciones, anticipos, inasistencia, aceptación)GET/PATCH /booking_settings/policy
Qué mensajes salenGET/PATCH /booking_settings/notifications
Alojamiento (habitaciones por noche, impuesto de hospedaje)GET/PATCH /booking_settings/lodging
Los links públicos para compartirGET /booking_settings/share
Paquetes de sesiones vendidos por adelantadoGET/POST /booking_packages, DELETE /booking_packages/{id}, y las sesiones que le quedan a un cliente en GET /customers/{customer_id}/package_credits
Notas sobre un clienteGET/POST /customers/{customer_id}/notes, DELETE …/notes/{id}

Una forma de vender desactivada no recibe nada nuevo, tampoco por la API: con Citas desactivado, los horarios por servicio y toda cita, serie o lugar en la lista de espera nuevos responden 403 con code: bookings_off; con Alojamiento desactivado, una estadía nueva responde code: lodging_off. Lo ya reservado sigue funcionando: moverlo, cancelarlo, cobrarlo y la recepción.

Un PATCH cambia solo los campos que envías, con las validaciones del panel; si no se puede, responde 422 con code: invalid_booking_settings y los mismos mensajes del panel.

Webhooks

Cada evento lleva el objeto como estaba en el momento del evento.

EventoCuándo
booking.createSe reservó una cita o un lugar en una clase, desde cualquier canal.
booking.confirmLa hora es del cliente: reservada sin pago, pagada o aceptada.
booking.rescheduleSe emite sobre la cita nueva cuando una cita se mueve.
booking.cancelCancelada; cancelled_by dice quién.
booking.refundSe devolvió lo que la cita había cobrado.
booking.no_showMarcada como inasistencia.
booking.completeLa visita ocurrió.
booking.check_in / booking.check_outEl huésped de una estadía llegó / salió.
gift_card.issue, .reload, .redeem, .release, .adjust, .refund_back, .refund_void, .expire, .voidUno por cada movimiento del saldo de una tarjeta, con la tarjeta y su transaction.
contract.send, .view, .sign, .decline, .expireUn contrato cambió de estado.

Sandbox

Las citas son nativas en un Sandbox: la misma agenda, links de pago que se pagan con la tarjeta de prueba y eventos que salen solo a los webhooks del Sandbox. El cargo por inasistencia, las devoluciones, cancelar una clase y el check-out corren sobre los pagos de prueba del Sandbox y nunca llegan a un procesador real. Ningún WhatsApp ni correo le llega a una persona real desde un Sandbox: un contrato enviado desde uno se comparte con su signing_url. El calendario externo de una habitación se guarda, pero nunca se descarga.

Agentes: CLI y MCP

Todas las operaciones de esta guía están en el catálogo de agentes, así que el CLI recurrente y el servidor MCP las corren sin código adicional. “Mueve la cita de Ana de las 3 al jueves” son tres llamadas:

recurrente bookings list --q Ana
recurrente bookings availability --booking-id bk_ab12cd34 --from 2026-10-08 --to 2026-10-09
recurrente bookings reschedule --booking-id bk_ab12cd34 --starts-at 2026-10-08T15:00:00-06:00

Las operaciones que mueven dinero necesitan que una persona confirme: --yes en el CLI, el permiso money en una conexión MCP.