Integra SmartCalendar con tu stack. Crea citas, gestiona pacientes y sincroniza bonos desde WooCommerce, Zapier, o cualquier aplicación.
Ve a Ajustes → API Keys en tu dashboard y crea una nueva clave con los permisos necesarios.
curl -X GET "https://app.smartcalendar.io/api/v1/appointments" \
-H "Authorization: Bearer sk_live_tu_clave_aqui"Pega una linea de codigo y tus clientes reservan desde tu web
Crear, leer, actualizar y cancelar citas desde cualquier sistema
Importar y mantener actualizados los datos de tus pacientes
Crear y redimir cupones desde WooCommerce u otras tiendas
Recibir notificaciones en tiempo real cuando algo cambie
La forma mas rapida de integrar SmartCalendar. Pega una linea de codigo y tus clientes pueden reservar, elegir tratamiento, seleccionar terapeuta y pagar — todo sin salir de tu web.
Calendario completo con todos los servicios
<script src="https://smartcalendar.io/widget.js"
data-widget-key="wgt_TU_CLAVE">
</script>
<div id="smartcalendar-widget"></div>Preselecciona un masaje concreto — el cliente va directo a elegir dia y hora
<script src="https://smartcalendar.io/widget.js"
data-widget-key="wgt_TU_CLAVE"
data-treatment-id="UUID_TRATAMIENTO">
</script>Solo muestra la disponibilidad de un terapeuta especifico
<script src="https://smartcalendar.io/widget.js"
data-widget-key="wgt_TU_CLAVE"
data-treatment-id="UUID_TRATAMIENTO"
data-staff-id="UUID_TERAPEUTA">
</script>Cuando un paciente compra un bono (por WooCommerce o en consulta), puedes enviarle un link directo para que reserve su cita. Si el bono esta vinculado a un tratamiento, el widget muestra automaticamente solo los horarios disponibles para ese tratamiento.
<!-- Opcion 1: Widget con bono pre-aplicado -->
<script src="https://smartcalendar.io/widget.js"
data-widget-key="wgt_TU_CLAVE"
data-bonus="BONO-XXXX-XXXX">
</script>
<!-- Opcion 2: Link directo (el widget recoge los parametros de la URL) -->
<!-- https://tuspa.com/reservar?bonus=BONO-XXXX-XXXX -->
<!-- Opcion 3: Link directo al widget hospedado -->
<!-- https://app.smartcalendar.io/widget/wgt_TU_CLAVE?bonus=BONO-XXXX-XXXX -->Si tu pagina de WordPress tiene parametros en la URL, el widget los recoge automaticamente. Esto es ideal para botones en tu web que enlazan a la pagina de reservas con datos pre-rellenados.
<!-- En cualquier pagina de tu WordPress -->
<a href="/reservar?treatment_id=UUID&staff_id=UUID"
class="button">
Reservar masaje con Eva
</a>
<!-- La pagina /reservar tiene el widget -->
<script src="https://smartcalendar.io/widget.js"
data-widget-key="wgt_TU_CLAVE">
</script>
<div id="smartcalendar-widget"></div>
<!-- El widget recoge treatment_id y staff_id de la URL -->| Parametro | Atributo data-* | Funcion |
|---|---|---|
| treatment_id | data-treatment-id | Preselecciona un tratamiento/servicio |
| staff_id | data-staff-id | Filtra a un terapeuta concreto |
| bonus | data-bonus | Aplica un codigo de bono automaticamente |
| date | data-date | Preselecciona fecha (YYYY-MM-DD) |
| time | data-time | Preselecciona hora (HH:mm) |
Para mayor control, puedes inicializar el widget desde JavaScript:
<div id="mi-widget"></div>
<script src="https://smartcalendar.io/widget.js"
data-widget-key="wgt_TU_CLAVE">
</script>
<script>
// Inicializar manualmente con opciones
var widget = SmartCalendar.init({
widgetKey: 'wgt_TU_CLAVE',
container: 'mi-widget',
treatmentId: 'uuid-del-masaje',
staffId: 'uuid-de-la-terapeuta',
// bonus: 'BONO-XXXX-XXXX',
// date: '2026-03-15',
// time: '10:00',
height: '800px',
});
// Escuchar evento de reserva completada
window.addEventListener('smartcalendar:booking', function(e) {
console.log('Reserva completada:', e.detail);
// Integrar con Google Analytics, Facebook Pixel, etc.
gtag('event', 'purchase', {
value: e.detail.total,
currency: 'EUR',
});
});
</script>El widget hereda los colores, logo y textos que configuras en Dashboard → Ajustes → Widgets. Tambien puedes ajustar dimensiones desde el embed:
<script src="https://smartcalendar.io/widget.js"
data-widget-key="wgt_TU_CLAVE"
data-width="100%"
data-height="800px"
data-theme="light">
</script>Para desarrolladores que necesitan mas control: conecta tu backend WordPress directamente con la API REST de SmartCalendar para gestionar reservas, bonos y disponibilidad programaticamente.
Nota: Si solo necesitas mostrar el calendario de reservas en tu web, usa el widget embed — es mucho mas sencillo.
GET /locationsGET /availabilityPOST /appointmentsPOST /bonusesAñade esto a tu functions.php o crea un plugin personalizado:
<?php
// Configuración SmartCalendar API
define('SMARTCALENDAR_API_KEY', 'sk_live_tu_clave_aqui');
define('SMARTCALENDAR_API_URL', 'https://app.smartcalendar.io/api/v1');
/**
* Helper para llamadas a la API de SmartCalendar
*/
function smartcalendar_api($endpoint, $method = 'GET', $body = null) {
$args = [
'method' => $method,
'headers' => [
'Authorization' => 'Bearer ' . SMARTCALENDAR_API_KEY,
'Content-Type' => 'application/json',
],
'timeout' => 30,
];
if ($body && in_array($method, ['POST', 'PUT', 'PATCH'])) {
$args['body'] = json_encode($body);
}
$response = wp_remote_request(SMARTCALENDAR_API_URL . $endpoint, $args);
if (is_wp_error($response)) {
return ['error' => $response->get_error_message()];
}
return json_decode(wp_remote_retrieve_body($response), true);
}Shortcode para mostrar un calendario de disponibilidad por salas:
<?php
/**
* Shortcode: [smartcalendar_availability]
* Muestra la disponibilidad de la semana con salas disponibles
*/
add_shortcode('smartcalendar_availability', function($atts) {
$atts = shortcode_atts(['days' => 7, 'location' => null], $atts);
$params = [
'start_date' => date('Y-m-d'),
'end_date' => date('Y-m-d', strtotime('+' . $atts['days'] . ' days')),
];
if ($atts['location']) {
$params['location_id'] = $atts['location'];
}
$data = smartcalendar_api('/availability?' . http_build_query($params));
if (!$data || !$data['success']) {
return '<p class="sc-error">No se pudo cargar la disponibilidad</p>';
}
$html = '<div class="sc-availability">';
// Mostrar salas disponibles
if (!empty($data['data']['locations'])) {
$html .= '<div class="sc-locations">';
foreach ($data['data']['locations'] as $location) {
$html .= '<span class="sc-location-badge">' . esc_html($location['name']) . '</span>';
}
$html .= '</div>';
}
// Mostrar días y slots
foreach ($data['data']['availability'] as $day) {
$html .= '<div class="sc-day">';
$html .= '<h4>' . esc_html($day['date']) . ' - ' . esc_html($day['day_name']) . '</h4>';
if (!$day['is_open']) {
$html .= '<p class="sc-closed">Cerrado</p>';
} else {
$html .= '<div class="sc-slots">';
foreach ($day['slots'] as $slot) {
if ($slot['available']) {
$rooms = count($slot['available_locations']);
$location_id = $slot['available_locations'][0]['id'] ?? '';
$html .= sprintf(
'<button class="sc-slot available" data-date="%s" data-time="%s" data-location="%s">
%s <small>(%d salas)</small>
</button>',
esc_attr($day['date']),
esc_attr($slot['time']),
esc_attr($location_id),
esc_html($slot['time']),
$rooms
);
}
}
$html .= '</div>';
}
$html .= '</div>';
}
$html .= '</div>';
return $html;
});Genera automáticamente un bono (sesiones o saldo) en SmartCalendar cuando se completa un pedido. Usa POST /bonuses — no confundir con /vouchers (cupones de descuento % o fijo).
<?php
/**
* Crear bono en SmartCalendar al completar pedido de WooCommerce
*
* Requisitos:
* - Producto WooCommerce con meta '_smartcalendar_plan_id' = UUID del physio_bonus_plan
* - Obtener plan_id desde GET /bonus-plans (bonus_type: sessions o balance)
*/
add_action('woocommerce_order_status_completed', function($order_id) {
$order = wc_get_order($order_id);
if (!$order) return;
foreach ($order->get_items() as $item) {
$product_id = $item->get_product_id();
$plan_id = get_post_meta($product_id, '_smartcalendar_plan_id', true);
if (!$plan_id) continue; // No es un producto de bono
// Crear bono en SmartCalendar (POST /bonuses)
$result = smartcalendar_api('/bonuses', 'POST', [
'plan_id' => $plan_id,
'patient_phone' => $order->get_billing_phone(),
'patient_name' => $order->get_billing_first_name() . ' ' . $order->get_billing_last_name(),
'amount_paid' => $item->get_total(),
'payment_method' => 'online',
'external_id' => 'woo_' . $order_id . '_' . $item->get_id(),
'external_source' => 'woocommerce',
]);
if ($result && $result['success']) {
$bonus_code = $result['data']['code'];
$order->add_order_note(
sprintf('Bono SmartCalendar creado: %s', $bonus_code)
);
$order->add_meta_data('_smartcalendar_bonus_' . $item->get_id(), $bonus_code);
$order->save();
}
}
});
/**
* Mostrar código de bono en la página de agradecimiento
*/
add_action('woocommerce_thankyou', function($order_id) {
$order = wc_get_order($order_id);
$bonuses = [];
foreach ($order->get_meta_data() as $meta) {
if (strpos($meta->key, '_smartcalendar_bonus_') === 0) {
$bonuses[] = $meta->value;
}
}
if (!empty($bonuses)) {
echo '<div class="sc-bonus-box">';
echo '<h3>🎟️ Tus códigos de bono</h3>';
echo '<p>Usa estos códigos para reservar tu cita:</p>';
foreach ($bonuses as $code) {
echo '<div class="sc-bonus-code"><code>' . esc_html($code) . '</code></div>';
}
echo '</div>';
}
});Handler para crear citas desde tu formulario de reservas:
<?php
/**
* AJAX handler para crear citas
*/
add_action('wp_ajax_smartcalendar_book', 'smartcalendar_book_appointment');
add_action('wp_ajax_nopriv_smartcalendar_book', 'smartcalendar_book_appointment');
function smartcalendar_book_appointment() {
// Verificar nonce
if (!wp_verify_nonce($_POST['nonce'], 'smartcalendar_book')) {
wp_send_json_error(['message' => 'Sesión expirada']);
}
// Validar campos
$required = ['phone', 'date', 'time', 'location_id'];
foreach ($required as $field) {
if (empty($_POST[$field])) {
wp_send_json_error(['message' => 'Campo requerido: ' . $field]);
}
}
// Formatear fecha/hora
$datetime = $_POST['date'] . 'T' . $_POST['time'] . ':00';
// Crear cita
$result = smartcalendar_api('/appointments', 'POST', [
'customer_phone' => sanitize_text_field($_POST['phone']),
'customer_name' => sanitize_text_field($_POST['name'] ?? ''),
'start_time' => $datetime,
'location_id' => sanitize_text_field($_POST['location_id']),
'notes' => sanitize_textarea_field($_POST['notes'] ?? ''),
'external_id' => 'wp_' . uniqid(),
'external_source' => 'wordpress',
]);
if ($result && $result['success']) {
wp_send_json_success([
'message' => '¡Cita reservada!',
'appointment_id' => $result['data']['id'],
]);
} else {
$error = $result['error'] ?? 'Error al crear la cita';
wp_send_json_error(['message' => $error]);
}
}
/**
* Enqueue scripts para el formulario de reservas
*/
add_action('wp_enqueue_scripts', function() {
wp_enqueue_script(
'smartcalendar-booking',
get_template_directory_uri() . '/js/smartcalendar-booking.js',
['jquery'],
'1.0.0',
true
);
wp_localize_script('smartcalendar-booking', 'scBooking', [
'ajaxUrl' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('smartcalendar_book'),
]);
});js/smartcalendar-booking.js:
// smartcalendar-booking.js
jQuery(function($) {
// Al hacer clic en un slot disponible
$('.sc-availability').on('click', '.sc-slot.available', function() {
const $slot = $(this);
const date = $slot.data('date');
const time = $slot.data('time');
const locationId = $slot.data('location');
// Marcar seleccionado
$('.sc-slot').removeClass('selected');
$slot.addClass('selected');
// Rellenar campos ocultos del formulario
$('#sc-date').val(date);
$('#sc-time').val(time);
$('#sc-location').val(locationId);
// Mostrar el formulario de datos
$('#sc-booking-form').slideDown();
});
// Enviar formulario
$('#sc-booking-form').on('submit', function(e) {
e.preventDefault();
const $form = $(this);
const $btn = $form.find('button[type="submit"]');
const originalText = $btn.text();
$btn.prop('disabled', true).text('Reservando...');
$.ajax({
url: scBooking.ajaxUrl,
method: 'POST',
data: {
action: 'smartcalendar_book',
nonce: scBooking.nonce,
phone: $('#sc-phone').val(),
name: $('#sc-name').val(),
date: $('#sc-date').val(),
time: $('#sc-time').val(),
location_id: $('#sc-location').val(),
notes: $('#sc-notes').val(),
},
success: function(response) {
if (response.success) {
// Mostrar mensaje de éxito
$form.html('<div class="sc-success">' +
'<h3>✅ ¡Cita reservada!</h3>' +
'<p>Te hemos enviado la confirmación por WhatsApp.</p>' +
'</div>');
} else {
alert(response.data.message || 'Error al reservar');
$btn.prop('disabled', false).text(originalText);
}
},
error: function() {
alert('Error de conexión');
$btn.prop('disabled', false).text(originalText);
}
});
});
});| Endpoint | Método | Descripción | Scope |
|---|---|---|---|
| /locations | GET | Listar salas | services:read |
| /treatments | GET | Listar tratamientos/servicios | services:read |
| /staff | GET | Listar empleados/terapeutas | services:read |
| /availability | GET | Consultar disponibilidad por salas | appointments:read |
| /appointments | POST | Crear cita | appointments:write |
| /appointments/:id | GET/PUT/DELETE | Obtener/Actualizar/Cancelar cita | appointments:* |
| /patients | GET/POST | Listar/Crear pacientes | patients:* |
| /patients/:id | GET/PUT | Obtener/Actualizar paciente | patients:* |
| /bonus-plans | GET | Listar planes de bonos (sesiones/saldo) | bonuses:read |
| /bonuses | GET/POST | Listar/Crear bonos (WooCommerce) | bonuses:* |
| /bonuses/:code | GET | Validar bono por código | bonuses:read |
| /bonuses/:code/redeem | POST | Deducir saldo de bono tipo balance | bonuses:write |
| /voucher-plans | GET | Listar planes de cupones (% o fijo) | vouchers:read |
| /vouchers | GET/POST | Listar/Crear cupones de descuento | vouchers:* |
| /vouchers/:code | GET/POST | Validar/Redimir cupón | vouchers:* |
| /webhooks | GET/POST | Listar/Crear webhooks | webhooks:* |
| /webhooks/:id | GET/PATCH/DELETE | Obtener/Actualizar/Eliminar webhook | webhooks:* |
Cada clinica puede tener un escaparate publico en /c/tu-slug donde los clientes ven servicios, compran bonos y reservan citas. Ideal para compartir un solo link en redes sociales o WhatsApp.
https://app.smartcalendar.io/c/tu-slug-personalizadoConfigura el slug en Dashboard → Ajustes → Widgets → Escaparate.
<!-- Link simple al escaparate -->
<a href="https://app.smartcalendar.io/c/mi-spa"
class="button">
Ver servicios y reservar
</a>
<!-- Link directo a un servicio concreto -->
<a href="https://app.smartcalendar.io/c/mi-spa?treatment_id=UUID">
Reservar masaje relajante
</a>Los clientes pueden comprar bonos directamente desde el escaparate. El pago se procesa con Stripe Checkout y el bono se genera automaticamente con su codigo unico. El paciente recibe el codigo por WhatsApp y puede usarlo para reservar desde el widget.
smartcalendar:bookingCuando un cliente completa una reserva en el widget embebido, se dispara un evento JavaScript en la pagina padre. Usalo para integrar con Google Analytics, Facebook Pixel, TikTok Ads o cualquier tracking.
window.addEventListener('smartcalendar:booking', function(e) {
// e.detail contiene:
{
id: "uuid-de-la-cita",
date: "2026-03-15",
time: "10:00",
location: "Sala 1", // o null
duration: 60, // minutos
total_price: 55.00, // EUR o null
total_price_cents: 5500, // centimos o null
service: "Masaje relajante", // nombre del servicio
bonus_applied: { // o null si no aplica
code: "BONO-XXXX-XXXX",
sessions_remaining: 4
}
}
});// Google Analytics 4
window.addEventListener('smartcalendar:booking', function(e) {
gtag('event', 'purchase', {
transaction_id: e.detail.id,
value: e.detail.total_price || 0,
currency: 'EUR',
items: [{
item_name: e.detail.service,
price: e.detail.total_price || 0,
}]
});
});
// Facebook Pixel
window.addEventListener('smartcalendar:booking', function(e) {
fbq('track', 'Schedule', {
value: e.detail.total_price || 0,
currency: 'EUR',
content_name: e.detail.service,
});
});
// Google Tag Manager (dataLayer)
window.addEventListener('smartcalendar:booking', function(e) {
dataLayer.push({
event: 'smartcalendar_booking',
booking_id: e.detail.id,
booking_value: e.detail.total_price,
booking_service: e.detail.service,
});
});SmartCalendar envia notificaciones HTTP a tu servidor cada vez que ocurre un evento. Configuralos en Dashboard → Ajustes → Webhooks. Ideal para integrar con Zapier, n8n, Make o tu backend.
| Evento | Se dispara cuando... |
|---|---|
| appointment.created | Se crea una nueva cita (widget, API o interno) |
| appointment.updated | Se modifica una cita (hora, sala, terapeuta...) |
| appointment.cancelled | Se cancela una cita |
| appointment.confirmed | El paciente confirma la cita |
| appointment.completed | La cita se marca como completada |
| patient.created | Se crea un nuevo paciente |
| patient.updated | Se actualizan datos del paciente |
| voucher.created | Se crea un bono de descuento |
| voucher.redeemed | Se canjea un bono |
| voucher.expired | Un bono caduca |
// POST a tu URL configurada
// Headers:
// Content-Type: application/json
// X-Webhook-Signature: hmac-sha256-hex
// X-Webhook-Event: appointment.created
// X-Webhook-Event-Id: evt_1234567890_abc
// User-Agent: SmartCalendar-Webhook/1.0
{
"event": "appointment.created",
"event_id": "evt_1234567890_abc",
"created_at": "2026-03-15T10:30:00.000Z",
"data": {
"appointment": {
"id": "uuid",
"start_time": "2026-03-15T10:00:00Z",
"end_time": "2026-03-15T11:00:00Z",
"status": "confirmed",
"customer_phone": "+34600000000",
"customer_name": "Eva Garcia",
"location_id": "uuid",
"assigned_staff_id": "uuid"
}
}
}Cada webhook incluye una firma HMAC-SHA256 en el header X-Webhook-Signature. Verificala con tu webhook secret para asegurar que el mensaje es autentico.
// Node.js
const crypto = require('crypto');
const signature = req.headers['x-webhook-signature'];
const expected = crypto
.createHmac('sha256', WEBHOOK_SECRET)
.update(JSON.stringify(req.body))
.digest('hex');
if (signature !== expected) {
return res.status(401).send('Invalid signature');
}Reintentos: Si tu servidor no responde con 2xx, se reintenta con backoff exponencial (1min, 2min, 4min... hasta 1h).
Desactivacion: Tras 10 fallos consecutivos, el webhook se desactiva automaticamente.
Idempotencia: Usa el event_id para deduplicar eventos.
Si usas Bookly para gestionar reservas o WooCommerce para vender bonos, puedes conectarlos para que SmartCalendar reciba las reservas y pedidos automaticamente.
Sincronizacion de reservas
1. URL del webhook
https://app.smartcalendar.io/api/webhooks/bookly2. Headers necesarios
X-Bookly-Signature: tu_webhook_secret
X-Clinic-Id: uuid_de_tu_clinica3. Eventos soportados
booking_created — Nueva reserva en Bookly → cita en SmartCalendarbooking_updated — Cambio de hora/sala → actualiza la citabooking_cancelled — Cancelacion → cancela la citaSmartCalendar crea/actualiza el paciente, la cita, sincroniza con Google Calendar y programa el recordatorio por WhatsApp.
Venta de bonos online
1. URL del webhook
https://app.smartcalendar.io/api/webhooks/woocommerce2. Configuracion en WooCommerce
WooCommerce → Ajustes → Avanzado → Webhooks → Anadir webhook.
Evento: Pedido completado. Formato: JSON.
X-WC-Webhook-Signature: (automatico por WooCommerce)
X-Clinic-Id: uuid_de_tu_clinica3. Mapeo de productos
Anade el meta _smartcalendar_plan_id al producto de WooCommerce con el UUID del plan de bono en SmartCalendar.
4. Flujo automatico
Activa las integraciones en Dashboard → Ajustes → Integraciones. Ahi configuras el webhook secret para verificar las firmas, el mapeo de SKU a planes de bono, y la sincronizacion bidireccional.
Explora todos los endpoints, prueba llamadas en vivo y genera código de ejemplo.