API REST v1

API para Desarrolladores

Integra SmartCalendar con tu stack. Crea citas, gestiona pacientes y sincroniza bonos desde WooCommerce, Zapier, o cualquier aplicación.

Flujos 1, 2, 3
Widget embebible
Escaparate publico
API Keys seguras
Rate limit: 60 req/min
Webhooks en tiempo real
Tracking de eventos
JSON REST
Quick Start

Tu primera llamada en 2 minutos

1

Obtén tu API Key

Ve a Ajustes → API Keys en tu dashboard y crea una nueva clave con los permisos necesarios.

2

Haz tu primera llamada

curl -X GET "https://app.smartcalendar.io/api/v1/appointments" \
  -H "Authorization: Bearer sk_live_tu_clave_aqui"

¿Qué puedes hacer con la API?

Embeber Widget

Pega una linea de codigo y tus clientes reservan desde tu web

Gestionar Citas

Crear, leer, actualizar y cancelar citas desde cualquier sistema

👤

Sincronizar Pacientes

Importar y mantener actualizados los datos de tus pacientes

🎟️

Bonos de Descuento

Crear y redimir cupones desde WooCommerce u otras tiendas

Webhooks

Recibir notificaciones en tiempo real cuando algo cambie

Integrar Widget de Reservas

Embeber el Widget en tu Web

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.

Widget basico

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>

Link a un tratamiento

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>

Link a un terapeuta

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>

Canjear un bono desde un link

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 -->

Parametros de URL automaticos

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.

Ejemplo: boton en WordPress

<!-- 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 -->

Parametros soportados

ParametroAtributo data-*Funcion
treatment_iddata-treatment-idPreselecciona un tratamiento/servicio
staff_iddata-staff-idFiltra a un terapeuta concreto
bonusdata-bonusAplica un codigo de bono automaticamente
datedata-datePreselecciona fecha (YYYY-MM-DD)
timedata-timePreselecciona hora (HH:mm)

Inicializacion programatica (JavaScript)

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>

Personalizacion visual

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>
Integracion avanzada: WordPress + WooCommerce + API REST

Guia Avanzada: WordPress con API

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.

1. Consultar Salas

GET /locations

2. Ver Disponibilidad

GET /availability

3. Crear Cita

POST /appointments

4. Gestionar Bonos

POST /bonuses

1
Configuración inicial

Añ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);
}

2
Mostrar disponibilidad

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;
});

3
WooCommerce: Vender bonos

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>';
    }
});

4
Crear cita (AJAX)

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'),
    ]);
});

5
JavaScript del formulario

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);
            }
        });
    });
});

Resumen de Endpoints

EndpointMétodoDescripciónScope
/locationsGETListar salasservices:read
/treatmentsGETListar tratamientos/serviciosservices:read
/staffGETListar empleados/terapeutasservices:read
/availabilityGETConsultar disponibilidad por salasappointments:read
/appointmentsPOSTCrear citaappointments:write
/appointments/:idGET/PUT/DELETEObtener/Actualizar/Cancelar citaappointments:*
/patientsGET/POSTListar/Crear pacientespatients:*
/patients/:idGET/PUTObtener/Actualizar pacientepatients:*
/bonus-plansGETListar planes de bonos (sesiones/saldo)bonuses:read
/bonusesGET/POSTListar/Crear bonos (WooCommerce)bonuses:*
/bonuses/:codeGETValidar bono por códigobonuses:read
/bonuses/:code/redeemPOSTDeducir saldo de bono tipo balancebonuses:write
/voucher-plansGETListar planes de cupones (% o fijo)vouchers:read
/vouchersGET/POSTListar/Crear cupones de descuentovouchers:*
/vouchers/:codeGET/POSTValidar/Redimir cupónvouchers:*
/webhooksGET/POSTListar/Crear webhookswebhooks:*
/webhooks/:idGET/PATCH/DELETEObtener/Actualizar/Eliminar webhookwebhooks:*
Escaparate publico

Microsite de Reservas y Venta Online

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.

URL del escaparate

https://app.smartcalendar.io/c/tu-slug-personalizado

Configura el slug en Dashboard → Ajustes → Widgets → Escaparate.

Que muestra el escaparate

  • Servicios/tratamientos con precio y duracion
  • Planes de bonos para compra online (Stripe Checkout)
  • Productos a la venta
  • Logo, colores y textos personalizados de la clinica
  • Boton "Reservar ahora" que abre el widget de reservas

Ejemplo: enlazar desde WordPress o redes

<!-- 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>

Compra de bonos desde el escaparate

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.

Evento de reserva completada

Evento smartcalendar:booking

Cuando 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.

Payload del evento

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
    }
  }
});

Ejemplos de integracion

// 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,
  });
});
Webhooks salientes

Webhooks: Recibir Notificaciones en Tiempo Real

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.

Eventos disponibles

EventoSe dispara cuando...
appointment.createdSe crea una nueva cita (widget, API o interno)
appointment.updatedSe modifica una cita (hora, sala, terapeuta...)
appointment.cancelledSe cancela una cita
appointment.confirmedEl paciente confirma la cita
appointment.completedLa cita se marca como completada
patient.createdSe crea un nuevo paciente
patient.updatedSe actualizan datos del paciente
voucher.createdSe crea un bono de descuento
voucher.redeemedSe canjea un bono
voucher.expiredUn bono caduca

Formato del payload

// 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"
    }
  }
}

Verificacion de firma

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.

Webhooks entrantes

Conectar WordPress: Bookly y WooCommerce

Si usas Bookly para gestionar reservas o WooCommerce para vender bonos, puedes conectarlos para que SmartCalendar reciba las reservas y pedidos automaticamente.

Bookly

Sincronizacion de reservas

1. URL del webhook

https://app.smartcalendar.io/api/webhooks/bookly

2. Headers necesarios

X-Bookly-Signature: tu_webhook_secret
X-Clinic-Id: uuid_de_tu_clinica

3. Eventos soportados

  • booking_created — Nueva reserva en Bookly → cita en SmartCalendar
  • booking_updated — Cambio de hora/sala → actualiza la cita
  • booking_cancelled — Cancelacion → cancela la cita

SmartCalendar crea/actualiza el paciente, la cita, sincroniza con Google Calendar y programa el recordatorio por WhatsApp.

WooCommerce

Venta de bonos online

1. URL del webhook

https://app.smartcalendar.io/api/webhooks/woocommerce

2. 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_clinica

3. 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

  • Pedido completado → Se crea el bono en SmartCalendar
  • Se envia WhatsApp al cliente con el codigo del bono
  • El codigo se sincroniza bidireccionalmente con WooCommerce

Configuracion en SmartCalendar

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.

Documentación Interactiva

Explora todos los endpoints, prueba llamadas en vivo y genera código de ejemplo.