curl --request POST \
--url https://api.craqui.com/v1/sessions/{id}/cancel \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"reason": "La instructora está enferma. Te esperamos el jueves."
}
'import requests
url = "https://api.craqui.com/v1/sessions/{id}/cancel"
payload = { "reason": "La instructora está enferma. Te esperamos el jueves." }
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({reason: 'La instructora está enferma. Te esperamos el jueves.'})
};
fetch('https://api.craqui.com/v1/sessions/{id}/cancel', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.craqui.com/v1/sessions/{id}/cancel",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'reason' => 'La instructora está enferma. Te esperamos el jueves.'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.craqui.com/v1/sessions/{id}/cancel"
payload := strings.NewReader("{\n \"reason\": \"La instructora está enferma. Te esperamos el jueves.\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.craqui.com/v1/sessions/{id}/cancel")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"reason\": \"La instructora está enferma. Te esperamos el jueves.\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.craqui.com/v1/sessions/{id}/cancel")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"reason\": \"La instructora está enferma. Te esperamos el jueves.\"\n}"
response = http.request(request)
puts response.read_body{
"id": "ses_01jnb07m4yxxe0s687jf750tkv",
"object": "session",
"livemode": true,
"class_id": "cls_01jryg07jeazdbx61dnx96ckmv",
"course_id": "crs_01jff81dk7rxtacmye5nanfp0h",
"center_id": "ctr_01j65pdnq74qvnh0953pzvtczg",
"room_id": "room_01jhweg897s9npa0tasfgt6a65",
"teacher_id": "tch_01jmwqh91chk154n8xwnaw5ynd",
"starts_at": "2026-12-02T19:00:00-03:00",
"ends_at": "2026-12-02T20:00:00-03:00",
"local_date": "2026-12-02",
"local_start_time": "19:00",
"local_end_time": "20:00",
"time_zone": "America/Montevideo",
"status": "cancelled",
"capacity": 20,
"booked_count": 0,
"waitlist_count": 0,
"available_spots": 20,
"created_at": "2026-11-04T03:00:00-03:00",
"updated_at": "2026-12-01T09:12:44-03:00"
}{
"type": "https://docs.craqui.com/errors/invalid_api_key",
"title": "La clave no es válida",
"status": 401,
"code": "invalid_api_key",
"request_id": "req_01hzx8m4k2a7d9q3f5w6y8z0bc",
"detail": "Revisa que copiaste la clave completa, incluido el prefijo (crq_live_ o crq_test_).",
"doc_url": "<string>",
"required_scope": "business:read",
"errors": [
{
"field": "limit",
"code": "invalid_limit",
"detail": "<string>"
}
],
"current_price": {
"amount_cents": 250000,
"currency": "UYU"
},
"expected_amount": {
"amount_cents": 250000,
"currency": "UYU"
},
"amount_at_stake": {
"amount_cents": 250000,
"currency": "UYU"
},
"existing_membership_id": "mem_01j1q27t44qvr6v2s50cv4rbvq",
"booking_ids": [
"bkg_01jx9eak0437zdf0yw0atg7g0r"
]
}{
"type": "https://docs.craqui.com/errors/revoked_api_key",
"title": "La clave fue revocada",
"status": 401,
"code": "revoked_api_key",
"detail": "Crea una clave nueva en Configuración → Integraciones.",
"request_id": "req_01hzx8m4k2a7d9q3f5w6y8z0bc"
}{
"type": "https://docs.craqui.com/errors/invalid_api_key",
"title": "La clave no es válida",
"status": 401,
"code": "invalid_api_key",
"request_id": "req_01hzx8m4k2a7d9q3f5w6y8z0bc",
"detail": "Revisa que copiaste la clave completa, incluido el prefijo (crq_live_ o crq_test_).",
"doc_url": "<string>",
"required_scope": "business:read",
"errors": [
{
"field": "limit",
"code": "invalid_limit",
"detail": "<string>"
}
],
"current_price": {
"amount_cents": 250000,
"currency": "UYU"
},
"expected_amount": {
"amount_cents": 250000,
"currency": "UYU"
},
"amount_at_stake": {
"amount_cents": 250000,
"currency": "UYU"
},
"existing_membership_id": "mem_01j1q27t44qvr6v2s50cv4rbvq",
"booking_ids": [
"bkg_01jx9eak0437zdf0yw0atg7g0r"
]
}{
"type": "https://docs.craqui.com/errors/invalid_api_key",
"title": "La clave no es válida",
"status": 401,
"code": "invalid_api_key",
"request_id": "req_01hzx8m4k2a7d9q3f5w6y8z0bc",
"detail": "Revisa que copiaste la clave completa, incluido el prefijo (crq_live_ o crq_test_).",
"doc_url": "<string>",
"required_scope": "business:read",
"errors": [
{
"field": "limit",
"code": "invalid_limit",
"detail": "<string>"
}
],
"current_price": {
"amount_cents": 250000,
"currency": "UYU"
},
"expected_amount": {
"amount_cents": 250000,
"currency": "UYU"
},
"amount_at_stake": {
"amount_cents": 250000,
"currency": "UYU"
},
"existing_membership_id": "mem_01j1q27t44qvr6v2s50cv4rbvq",
"booking_ids": [
"bkg_01jx9eak0437zdf0yw0atg7g0r"
]
}{
"type": "https://docs.craqui.com/errors/sandbox_unavailable",
"title": "Tu estudio de prueba no está listo",
"status": 409,
"code": "sandbox_unavailable",
"detail": "Restablece tus datos de prueba en Configuración → Integraciones y vuelve a intentar.",
"request_id": "req_01hzx8m4k2a7d9q3f5w6y8z0bc"
}{
"type": "https://docs.craqui.com/errors/invalid_api_key",
"title": "La clave no es válida",
"status": 401,
"code": "invalid_api_key",
"request_id": "req_01hzx8m4k2a7d9q3f5w6y8z0bc",
"detail": "Revisa que copiaste la clave completa, incluido el prefijo (crq_live_ o crq_test_).",
"doc_url": "<string>",
"required_scope": "business:read",
"errors": [
{
"field": "limit",
"code": "invalid_limit",
"detail": "<string>"
}
],
"current_price": {
"amount_cents": 250000,
"currency": "UYU"
},
"expected_amount": {
"amount_cents": 250000,
"currency": "UYU"
},
"amount_at_stake": {
"amount_cents": 250000,
"currency": "UYU"
},
"existing_membership_id": "mem_01j1q27t44qvr6v2s50cv4rbvq",
"booking_ids": [
"bkg_01jx9eak0437zdf0yw0atg7g0r"
]
}{
"type": "https://docs.craqui.com/errors/invalid_api_key",
"title": "La clave no es válida",
"status": 401,
"code": "invalid_api_key",
"request_id": "req_01hzx8m4k2a7d9q3f5w6y8z0bc",
"detail": "Revisa que copiaste la clave completa, incluido el prefijo (crq_live_ o crq_test_).",
"doc_url": "<string>",
"required_scope": "business:read",
"errors": [
{
"field": "limit",
"code": "invalid_limit",
"detail": "<string>"
}
],
"current_price": {
"amount_cents": 250000,
"currency": "UYU"
},
"expected_amount": {
"amount_cents": 250000,
"currency": "UYU"
},
"amount_at_stake": {
"amount_cents": 250000,
"currency": "UYU"
},
"existing_membership_id": "mem_01j1q27t44qvr6v2s50cv4rbvq",
"booking_ids": [
"bkg_01jx9eak0437zdf0yw0atg7g0r"
]
}{
"type": "https://docs.craqui.com/errors/invalid_api_key",
"title": "La clave no es válida",
"status": 401,
"code": "invalid_api_key",
"request_id": "req_01hzx8m4k2a7d9q3f5w6y8z0bc",
"detail": "Revisa que copiaste la clave completa, incluido el prefijo (crq_live_ o crq_test_).",
"doc_url": "<string>",
"required_scope": "business:read",
"errors": [
{
"field": "limit",
"code": "invalid_limit",
"detail": "<string>"
}
],
"current_price": {
"amount_cents": 250000,
"currency": "UYU"
},
"expected_amount": {
"amount_cents": 250000,
"currency": "UYU"
},
"amount_at_stake": {
"amount_cents": 250000,
"currency": "UYU"
},
"existing_membership_id": "mem_01j1q27t44qvr6v2s50cv4rbvq",
"booking_ids": [
"bkg_01jx9eak0437zdf0yw0atg7g0r"
]
}Cancelar una sesión
Cancela una sesión, igual que desde Craqui: se cancelan todas sus reservas (confirmadas y en lista de
espera) y vuelven los créditos de las confirmadas. Nadie entra de la lista de espera, porque la sesión ya
no se da. Se les avisa a quienes tenían reserva y a quienes iban a ir, por los canales que el estudio
tenga encendidos, con el reason que mandes. Responde la sesión como queda, con status: cancelled.
No admite notify (400 notify_not_supported): cancelar una sesión siempre avisa. Tu estudio de prueba
no le avisa a nadie. Si la sesión ya estaba cancelada, responde 200 con la sesión y no cancela, devuelve
ni avisa nada de nuevo. Con dry_run=true responde 200 con la vista previa: cuántas reservas se
cancelarían y cuántos créditos volverían.
Rechazos (409): session_started (por la API no se cancela una sesión que ya empezó: se corrige desde
Craqui) y session_on_vacation (el estudio ya la suspendió por vacaciones o un feriado: sus reservas ya se
cancelaron y se avisó a quienes iban a ir). Una sesión que no es de tu negocio, o de un workshop, responde
404 not_found.
Una escritura: lleva Idempotency-Key (salvo con dry_run=true), solo para estudios (en una academia
responde wrong_vertical), y solo si tu negocio tiene habilitada la escritura por la API
(write_access_disabled si no). Un campo que el cuerpo no declara responde validation_failed con
unknown_field. Cuenta para el límite de escrituras (30 por minuto).
curl --request POST \
--url https://api.craqui.com/v1/sessions/{id}/cancel \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"reason": "La instructora está enferma. Te esperamos el jueves."
}
'import requests
url = "https://api.craqui.com/v1/sessions/{id}/cancel"
payload = { "reason": "La instructora está enferma. Te esperamos el jueves." }
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({reason: 'La instructora está enferma. Te esperamos el jueves.'})
};
fetch('https://api.craqui.com/v1/sessions/{id}/cancel', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.craqui.com/v1/sessions/{id}/cancel",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'reason' => 'La instructora está enferma. Te esperamos el jueves.'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.craqui.com/v1/sessions/{id}/cancel"
payload := strings.NewReader("{\n \"reason\": \"La instructora está enferma. Te esperamos el jueves.\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.craqui.com/v1/sessions/{id}/cancel")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"reason\": \"La instructora está enferma. Te esperamos el jueves.\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.craqui.com/v1/sessions/{id}/cancel")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"reason\": \"La instructora está enferma. Te esperamos el jueves.\"\n}"
response = http.request(request)
puts response.read_body{
"id": "ses_01jnb07m4yxxe0s687jf750tkv",
"object": "session",
"livemode": true,
"class_id": "cls_01jryg07jeazdbx61dnx96ckmv",
"course_id": "crs_01jff81dk7rxtacmye5nanfp0h",
"center_id": "ctr_01j65pdnq74qvnh0953pzvtczg",
"room_id": "room_01jhweg897s9npa0tasfgt6a65",
"teacher_id": "tch_01jmwqh91chk154n8xwnaw5ynd",
"starts_at": "2026-12-02T19:00:00-03:00",
"ends_at": "2026-12-02T20:00:00-03:00",
"local_date": "2026-12-02",
"local_start_time": "19:00",
"local_end_time": "20:00",
"time_zone": "America/Montevideo",
"status": "cancelled",
"capacity": 20,
"booked_count": 0,
"waitlist_count": 0,
"available_spots": 20,
"created_at": "2026-11-04T03:00:00-03:00",
"updated_at": "2026-12-01T09:12:44-03:00"
}{
"type": "https://docs.craqui.com/errors/invalid_api_key",
"title": "La clave no es válida",
"status": 401,
"code": "invalid_api_key",
"request_id": "req_01hzx8m4k2a7d9q3f5w6y8z0bc",
"detail": "Revisa que copiaste la clave completa, incluido el prefijo (crq_live_ o crq_test_).",
"doc_url": "<string>",
"required_scope": "business:read",
"errors": [
{
"field": "limit",
"code": "invalid_limit",
"detail": "<string>"
}
],
"current_price": {
"amount_cents": 250000,
"currency": "UYU"
},
"expected_amount": {
"amount_cents": 250000,
"currency": "UYU"
},
"amount_at_stake": {
"amount_cents": 250000,
"currency": "UYU"
},
"existing_membership_id": "mem_01j1q27t44qvr6v2s50cv4rbvq",
"booking_ids": [
"bkg_01jx9eak0437zdf0yw0atg7g0r"
]
}{
"type": "https://docs.craqui.com/errors/revoked_api_key",
"title": "La clave fue revocada",
"status": 401,
"code": "revoked_api_key",
"detail": "Crea una clave nueva en Configuración → Integraciones.",
"request_id": "req_01hzx8m4k2a7d9q3f5w6y8z0bc"
}{
"type": "https://docs.craqui.com/errors/invalid_api_key",
"title": "La clave no es válida",
"status": 401,
"code": "invalid_api_key",
"request_id": "req_01hzx8m4k2a7d9q3f5w6y8z0bc",
"detail": "Revisa que copiaste la clave completa, incluido el prefijo (crq_live_ o crq_test_).",
"doc_url": "<string>",
"required_scope": "business:read",
"errors": [
{
"field": "limit",
"code": "invalid_limit",
"detail": "<string>"
}
],
"current_price": {
"amount_cents": 250000,
"currency": "UYU"
},
"expected_amount": {
"amount_cents": 250000,
"currency": "UYU"
},
"amount_at_stake": {
"amount_cents": 250000,
"currency": "UYU"
},
"existing_membership_id": "mem_01j1q27t44qvr6v2s50cv4rbvq",
"booking_ids": [
"bkg_01jx9eak0437zdf0yw0atg7g0r"
]
}{
"type": "https://docs.craqui.com/errors/invalid_api_key",
"title": "La clave no es válida",
"status": 401,
"code": "invalid_api_key",
"request_id": "req_01hzx8m4k2a7d9q3f5w6y8z0bc",
"detail": "Revisa que copiaste la clave completa, incluido el prefijo (crq_live_ o crq_test_).",
"doc_url": "<string>",
"required_scope": "business:read",
"errors": [
{
"field": "limit",
"code": "invalid_limit",
"detail": "<string>"
}
],
"current_price": {
"amount_cents": 250000,
"currency": "UYU"
},
"expected_amount": {
"amount_cents": 250000,
"currency": "UYU"
},
"amount_at_stake": {
"amount_cents": 250000,
"currency": "UYU"
},
"existing_membership_id": "mem_01j1q27t44qvr6v2s50cv4rbvq",
"booking_ids": [
"bkg_01jx9eak0437zdf0yw0atg7g0r"
]
}{
"type": "https://docs.craqui.com/errors/sandbox_unavailable",
"title": "Tu estudio de prueba no está listo",
"status": 409,
"code": "sandbox_unavailable",
"detail": "Restablece tus datos de prueba en Configuración → Integraciones y vuelve a intentar.",
"request_id": "req_01hzx8m4k2a7d9q3f5w6y8z0bc"
}{
"type": "https://docs.craqui.com/errors/invalid_api_key",
"title": "La clave no es válida",
"status": 401,
"code": "invalid_api_key",
"request_id": "req_01hzx8m4k2a7d9q3f5w6y8z0bc",
"detail": "Revisa que copiaste la clave completa, incluido el prefijo (crq_live_ o crq_test_).",
"doc_url": "<string>",
"required_scope": "business:read",
"errors": [
{
"field": "limit",
"code": "invalid_limit",
"detail": "<string>"
}
],
"current_price": {
"amount_cents": 250000,
"currency": "UYU"
},
"expected_amount": {
"amount_cents": 250000,
"currency": "UYU"
},
"amount_at_stake": {
"amount_cents": 250000,
"currency": "UYU"
},
"existing_membership_id": "mem_01j1q27t44qvr6v2s50cv4rbvq",
"booking_ids": [
"bkg_01jx9eak0437zdf0yw0atg7g0r"
]
}{
"type": "https://docs.craqui.com/errors/invalid_api_key",
"title": "La clave no es válida",
"status": 401,
"code": "invalid_api_key",
"request_id": "req_01hzx8m4k2a7d9q3f5w6y8z0bc",
"detail": "Revisa que copiaste la clave completa, incluido el prefijo (crq_live_ o crq_test_).",
"doc_url": "<string>",
"required_scope": "business:read",
"errors": [
{
"field": "limit",
"code": "invalid_limit",
"detail": "<string>"
}
],
"current_price": {
"amount_cents": 250000,
"currency": "UYU"
},
"expected_amount": {
"amount_cents": 250000,
"currency": "UYU"
},
"amount_at_stake": {
"amount_cents": 250000,
"currency": "UYU"
},
"existing_membership_id": "mem_01j1q27t44qvr6v2s50cv4rbvq",
"booking_ids": [
"bkg_01jx9eak0437zdf0yw0atg7g0r"
]
}{
"type": "https://docs.craqui.com/errors/invalid_api_key",
"title": "La clave no es válida",
"status": 401,
"code": "invalid_api_key",
"request_id": "req_01hzx8m4k2a7d9q3f5w6y8z0bc",
"detail": "Revisa que copiaste la clave completa, incluido el prefijo (crq_live_ o crq_test_).",
"doc_url": "<string>",
"required_scope": "business:read",
"errors": [
{
"field": "limit",
"code": "invalid_limit",
"detail": "<string>"
}
],
"current_price": {
"amount_cents": 250000,
"currency": "UYU"
},
"expected_amount": {
"amount_cents": 250000,
"currency": "UYU"
},
"amount_at_stake": {
"amount_cents": 250000,
"currency": "UYU"
},
"existing_membership_id": "mem_01j1q27t44qvr6v2s50cv4rbvq",
"booking_ids": [
"bkg_01jx9eak0437zdf0yw0atg7g0r"
]
}Authorizations
Clave del negocio. sk es una clave completa (todo lo que el rol de quien la creó puede dar)
y rk una restringida a los permisos que se eligieron al crearla. Solo se usa desde un
servidor: un pedido desde un navegador se rechaza con browser_not_allowed.
Scopes
Cancelar sesiones.
Headers
Versión de la API para este pedido (YYYY-MM-DD). Si no la mandas, se usa la versión fijada en
la clave cuando se creó.
^\d{4}-\d{2}-\d{2}$"2026-12-01"
Obligatorio en todo pedido que crea o cambia algo, salvo con dry_run=true. Un valor único por
operación (por ejemplo un UUID). Si repites el pedido con la misma clave y el mismo cuerpo dentro de 24
horas, recibes la misma respuesta (con el header Idempotent-Replayed: true) sin que se repita el efecto,
también la misma respuesta de error: para intentar de nuevo algo que se rechazó, usa una clave nueva.
Con un dry_run=true la clave se ignora y no se guarda: el pedido real puede usar la misma. Pasadas las 24
horas, repetir una reserva con la misma clave y el mismo cuerpo sigue devolviendo la reserva que se hizo
(como está ahora), y la misma clave con otro cuerpo responde idempotency_key_reused.
1 - 255Path Parameters
El id de la sesión (ses_…).
Id de una sesión (una fecha de una clase).
^ses_[0-7][0-9a-hjkmnp-tv-z]{25}$"ses_01jnb07m4yxxe0s687jf750tkv"
Query Parameters
true para ver qué pasaría sin hacerlo: Craqui evalúa el pedido con las mismas reglas que el real y
responde 200 con un objeto preview, sin escribir nada ni avisarle a nadie. Cuenta para el límite de
escrituras. false (o sin el parámetro) hace el pedido real. Es el único parámetro de consulta de una
escritura.
Body
El cuerpo es opcional. No lleva notify: cancelar una sesión siempre avisa a quienes iban a ir
(400 notify_not_supported).
El motivo, en una frase. Les llega a las personas avisadas.
200Response
La sesión como quedó, o con dry_run=true la vista previa (object dice cuál).
- Option 1
- Option 2
Una sesión: una fecha de una clase, con su horario, quién la da y sus lugares. Solo sesiones de clases: los workshops no están en esta versión.
Id de una sesión (una fecha de una clase).
^ses_[0-7][0-9a-hjkmnp-tv-z]{25}$"ses_01jnb07m4yxxe0s687jf750tkv"
"session"false si el objeto es de tu estudio de prueba (claves crq_test_); true con claves crq_live_.
Id de una clase (el grupo con su horario semanal).
^cls_[0-7][0-9a-hjkmnp-tv-z]{25}$"cls_01jryg07jeazdbx61dnx96ckmv"
Id de una disciplina.
^crs_[0-7][0-9a-hjkmnp-tv-z]{25}$"crs_01jff81dk7rxtacmye5nanfp0h"
Id de una sede.
^ctr_[0-7][0-9a-hjkmnp-tv-z]{25}$"ctr_01j65pdnq74qvnh0953pzvtczg"
El salón de esta sesión, si tiene uno asignado.
^room_[0-7][0-9a-hjkmnp-tv-z]{25}$"room_01jhweg897s9npa0tasfgt6a65"
Quien da esta sesión, con la suplencia aplicada (igual que el calendario del estudio). null
si no tiene instructor asignado.
^tch_[0-7][0-9a-hjkmnp-tv-z]{25}$"tch_01jmwqh91chk154n8xwnaw5ynd"
El inicio, con el offset del estudio en ese momento. Una hora local que no existe por el
cambio de horario (por ejemplo 00:30 la noche en que se adelanta el reloj) se corre una hora,
igual que al reservar: en ese caso starts_at y local_start_time no coinciden.
"2026-12-02T19:00:00-03:00"
El fin. Una clase que cruza la medianoche termina al día siguiente.
"2026-12-02T19:00:00-03:00"
Fecha local del negocio, YYYY-MM-DD.
^\d{4}-\d{2}-\d{2}$"2026-12-02"
Hora local del negocio, HH:MM (24 horas).
^\d{2}:\d{2}$"19:00"
Hora local del negocio, HH:MM (24 horas).
^\d{2}:\d{2}$"19:00"
La zona horaria del estudio (IANA). null si el estudio no eligió una; los instantes salen en +00:00.
"America/Montevideo"
scheduled, cancelled (el estudio la canceló) o studio_closed (el estudio cerró ese día).
La lista puede crecer: trata un valor que no conoces como una sesión que no se da.
scheduled, cancelled, studio_closed El cupo de la sesión. null si la clase no tiene cupo.
Los lugares tomados: reservas confirmadas, asistidas y ausentes hasta que la sesión empieza. Es la misma cuenta que usa Craqui al reservar.
x >= 0Cuántas personas esperan en la lista de espera.
x >= 0capacity - booked_count, nunca menos de 0. null si la clase no tiene cupo.
x >= 0Instante en RFC 3339 con el offset del negocio en ese momento.
"2026-12-02T19:00:00-03:00"
Instante en RFC 3339 con el offset del negocio en ese momento.
"2026-12-02T19:00:00-03:00"

