Endpoints de páginas de reserva (agendas tipo Calendly), sus reuniones agendadas y el grid combinado del calendario . Incluye además la API pública de booking (sin autenticación), que es la que usa la página de reserva que ve el invitado.
Cuelgan de /workspaces/:workspaceId/calendar/schedulers.
POST /workspaces/:workspaceId/calendar/schedulers
Copiar
curl -X POST "https://api.waiify.com/workspaces/WORKSPACE_ID/calendar/schedulers" \
-H "Authorization: Bearer TU_API_KEY" \
-H "Content-Type: application/json" \
"title": "Demo de producto",
"hosts": [{ "userId": "user_ab12cd34ef" }],
{ "weekday": 1, "startMinute": 540, "endMinute": 1020 }
"bookingWindowType": "ROLLING",
'https://api.waiify.com/workspaces/WORKSPACE_ID/calendar/schedulers' ,
Authorization: 'Bearer TU_API_KEY' ,
'Content-Type' : 'application/json' ,
title: 'Demo de producto' ,
hosts: [{ userId: 'user_ab12cd34ef' }],
{ weekday: 1 , startMinute: 540 , endMinute: 1020 },
bookingWindowType: 'ROLLING' ,
const { data : page } = await res. json ();
"https://api.waiify.com/workspaces/WORKSPACE_ID/calendar/schedulers" ,
headers = { "Authorization" : "Bearer TU_API_KEY" },
"title" : "Demo de producto" ,
"hosts" : [{ "userId" : "user_ab12cd34ef" }],
{ "weekday" : 1 , "startMinute" : 540 , "endMinute" : 1020 }
"bookingWindowType" : "ROLLING" ,
page = res.json()[ "data" ]
"message" : "Agenda creada" ,
"id" : "sched_ab12cd34ef" ,
"workspaceId" : "ws_ab12cd34ef" ,
"title" : "Demo de producto" ,
"slug" : "demo-de-producto" ,
"timezone" : "America/Mexico_City" ,
{ "id" : "shost_ab12cd34ef" , "userId" : "user_ab12cd34ef" , "role" : "PRIMARY" , "priority" : 0 }
{ "id" : "rule_ab12cd34ef" , "weekday" : 1 , "startMinute" : 540 , "endMinute" : 1020 }
GET /workspaces/:workspaceId/calendar/schedulers
Copiar
curl "https://api.waiify.com/workspaces/WORKSPACE_ID/calendar/schedulers?status=ACTIVE&page=1" \
-H "Authorization: Bearer TU_API_KEY"
'https://api.waiify.com/workspaces/WORKSPACE_ID/calendar/schedulers?page=1' ,
{ headers: { Authorization: 'Bearer TU_API_KEY' } }
const { data : pages , pagination } = await res. json ();
"https://api.waiify.com/workspaces/WORKSPACE_ID/calendar/schedulers" ,
headers = { "Authorization" : "Bearer TU_API_KEY" },
pages, pagination = body[ "data" ], body[ "pagination" ]
"id" : "sched_ab12cd34ef" ,
"title" : "Demo de producto" ,
"slug" : "demo-de-producto" ,
"timezone" : "America/Mexico_City" ,
"locationType" : "GOOGLE_MEET" ,
"organizer" : "Ana Torres" ,
"createdAt" : "2026-06-17T10:00:00.000Z" ,
"updatedAt" : "2026-06-20T10:00:00.000Z"
"pagination" : { "page" : 1 , "limit" : 25 , "total" : 1 , "totalPages" : 1 }
Cuelgan de /workspaces/:workspaceId/calendar/meetings. Son las reservas creadas por invitados (por la API pública de booking) o directamente por el equipo.
GET /workspaces/:workspaceId/calendar/meetings
Copiar
curl "https://api.waiify.com/workspaces/WORKSPACE_ID/calendar/meetings?timeframe=upcoming" \
-H "Authorization: Bearer TU_API_KEY"
'https://api.waiify.com/workspaces/WORKSPACE_ID/calendar/meetings?timeframe=upcoming' ,
{ headers: { Authorization: 'Bearer TU_API_KEY' } }
const { data : meetings , pagination } = await res. json ();
"https://api.waiify.com/workspaces/WORKSPACE_ID/calendar/meetings" ,
headers = { "Authorization" : "Bearer TU_API_KEY" },
params = { "timeframe" : "upcoming" },
meetings, pagination = body[ "data" ], body[ "pagination" ]
"pageId" : "sched_ab12cd34ef" ,
"schedulerTitle" : "Demo de producto" ,
"schedulerType" : "INDIVIDUAL" ,
"guestName" : "Juan Pérez" ,
"guestEmail" : "juan@example.com" ,
"start" : "2026-07-01T15:00:00.000Z" ,
"end" : "2026-07-01T15:30:00.000Z" ,
"locationType" : "GOOGLE_MEET" ,
"pagination" : { "page" : 1 , "limit" : 25 , "total" : 1 , "totalPages" : 1 }
PATCH /workspaces/:workspaceId/calendar/meetings/:id/cancel
Copiar
curl -X PATCH "https://api.waiify.com/workspaces/WORKSPACE_ID/calendar/meetings/MEETING_ID/cancel" \
-H "Authorization: Bearer TU_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "reason": "El cliente reagendó por otro canal" }'
'https://api.waiify.com/workspaces/WORKSPACE_ID/calendar/meetings/MEETING_ID/cancel' ,
Authorization: 'Bearer TU_API_KEY' ,
'Content-Type' : 'application/json' ,
body: JSON . stringify ({ reason: 'El cliente reagendó por otro canal' }),
"https://api.waiify.com/workspaces/WORKSPACE_ID/calendar/meetings/MEETING_ID/cancel" ,
headers = { "Authorization" : "Bearer TU_API_KEY" },
json = { "reason" : "El cliente reagendó por otro canal" },
"message" : "Reunión cancelada" ,
"cancelledAt" : "2026-06-25T12:00:00.000Z" ,
"cancelReason" : "El cliente reagendó por otro canal"
Vista unificada de reuniones ya agendadas y bloques de disponibilidad libre en un rango, la que alimenta el calendario del dashboard.
GET /workspaces/:workspaceId/calendar/grid
Copiar
curl "https://api.waiify.com/workspaces/WORKSPACE_ID/calendar/grid?from=2026-07-01T00:00:00Z&to=2026-07-08T00:00:00Z" \
-H "Authorization: Bearer TU_API_KEY"
const params = new URLSearchParams ({
from: '2026-07-01T00:00:00Z' ,
to: '2026-07-08T00:00:00Z' ,
`https://api.waiify.com/workspaces/WORKSPACE_ID/calendar/grid?${ params }` ,
{ headers: { Authorization: 'Bearer TU_API_KEY' } }
const { data } = await res. json ();
"https://api.waiify.com/workspaces/WORKSPACE_ID/calendar/grid" ,
headers = { "Authorization" : "Bearer TU_API_KEY" },
params = { "from" : "2026-07-01T00:00:00Z" , "to" : "2026-07-08T00:00:00Z" },
data = res.json()[ "data" ]
"schedulerTitle" : "Demo de producto" ,
"start" : "2026-07-01T15:00:00.000Z" ,
"end" : "2026-07-01T15:30:00.000Z" ,
"locationType" : "GOOGLE_MEET"
"id" : "sched_ab12cd34ef:2026-07-01:540" ,
"schedulerId" : "sched_ab12cd34ef" ,
"title" : "Demo de producto" ,
"start" : "2026-07-01T09:00:00.000Z" ,
"end" : "2026-07-01T15:00:00.000Z" ,
"accountDisconnected" : false
Sin autenticación — la usa la página pública que ve el invitado externo (/agendar/:pageId en el dashboard). No lleva Authorization, así que llevan rate limiting propio : 60 solicitudes/minuto en las de lectura, 10 solicitudes/hora en las de escritura (reservar/cancelar).
Precaución
pageId es el id de la página de reserva (no el slug ni el workspace), y token es el cancelToken que recibe el invitado al reservar. Solo se resuelven agendas en estado ACTIVE; una DRAFT, PAUSED o ARCHIVED responde 404 en estos endpoints públicos.
GET /booking/:pageId
Copiar
curl "https://api.waiify.com/booking/PAGE_ID"
const res = await fetch ( 'https://api.waiify.com/booking/PAGE_ID' );
const { data : page } = await res. json ();
res = requests.get( "https://api.waiify.com/booking/PAGE_ID" )
page = res.json()[ "data" ]
"id" : "sched_ab12cd34ef" ,
"title" : "Demo de producto" ,
"description" : "Una llamada de 30 minutos para conocer tu caso." ,
"timezone" : "America/Mexico_City" ,
"locationType" : "GOOGLE_MEET" ,
"requireGuestEmail" : true ,
"bookingPageName" : "Ana Torres" ,
"bookingPagePhoto" : null ,
"allowGuestInvitees" : true ,
{ "id" : "field_ab12cd34ef" , "label" : "¿Qué te gustaría revisar?" , "type" : "TEXTAREA" , "required" : false , "options" : [] }
GET /booking/:pageId/availability
Copiar
curl "https://api.waiify.com/booking/PAGE_ID/availability?from=2026-07-01&to=2026-07-07"
const params = new URLSearchParams ({ from: '2026-07-01' , to: '2026-07-07' });
`https://api.waiify.com/booking/PAGE_ID/availability?${ params }`
const { data : slots } = await res. json ();
"https://api.waiify.com/booking/PAGE_ID/availability" ,
params = { "from" : "2026-07-01" , "to" : "2026-07-07" },
slots = res.json()[ "data" ]
{ "start" : "2026-07-01T15:00:00.000Z" , "end" : "2026-07-01T15:30:00.000Z" },
{ "start" : "2026-07-01T15:30:00.000Z" , "end" : "2026-07-01T16:00:00.000Z" }
POST /booking/:pageId
Copiar
Precaución
El horario se revalida por completo en el servidor (disponibilidad real, antelación mínima, rango, buffers, tope diario y ocupación del anfitrión) — enviar un start fuera de lo que devolvió availability responde 400 o 409.
curl -X POST "https://api.waiify.com/booking/PAGE_ID" \
-H "Content-Type: application/json" \
"guestName": "Juan Pérez",
"guestEmail": "juan@example.com",
"start": "2026-07-01T15:00:00.000Z"
const res = await fetch ( 'https://api.waiify.com/booking/PAGE_ID' , {
headers: { 'Content-Type' : 'application/json' },
guestEmail: 'juan@example.com' ,
start: '2026-07-01T15:00:00.000Z' ,
const { data : booking } = await res. json ();
"https://api.waiify.com/booking/PAGE_ID" ,
"guestName" : "Juan Pérez" ,
"guestEmail" : "juan@example.com" ,
"start" : "2026-07-01T15:00:00.000Z" ,
booking = res.json()[ "data" ]
"message" : "Reserva confirmada" ,
"cancelToken" : "cnl_ab12cd34ef" ,
"start" : "2026-07-01T15:00:00.000Z" ,
"end" : "2026-07-01T15:30:00.000Z" ,
"guestTimezone" : "America/Mexico_City"
POST /booking/cancel/:token
Copiar
curl -X POST "https://api.waiify.com/booking/cancel/CANCEL_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "reason": "Ya no puedo asistir" }'
'https://api.waiify.com/booking/cancel/CANCEL_TOKEN' ,
headers: { 'Content-Type' : 'application/json' },
body: JSON . stringify ({ reason: 'Ya no puedo asistir' }),
const { data : booking } = await res. json ();
"https://api.waiify.com/booking/cancel/CANCEL_TOKEN" ,
json = { "reason" : "Ya no puedo asistir" },
booking = res.json()[ "data" ]
"message" : "Reserva cancelada" ,
"title" : "Demo de producto" ,
"start" : "2026-07-01T15:00:00.000Z" ,
"end" : "2026-07-01T15:30:00.000Z" ,
"timezone" : "America/Mexico_City" ,
"guestName" : "Juan Pérez" ,
"locationType" : "GOOGLE_MEET" ,
"cancelledAt" : "2026-06-25T12:00:00.000Z" ,
"cancelReason" : "Ya no puedo asistir"