> ## Documentation Index
> Fetch the complete documentation index at: https://docs.craqui.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Listar sesiones

> El horario del estudio: las sesiones de sus clases entre dos fechas locales, en orden cronológico,
con quién las da (con la suplencia aplicada) y sus lugares. Las canceladas y las de días cerrados no
vienen, salvo con `include_cancelled=true`.

`local_date[gte]` y `local_date[lte]` son obligatorios: 31 días como máximo, y 14 con
`has_capacity` (`range_too_long`).

        Paginada por cursor: para sincronizar todo, pide `limit=100` y sigue `next_cursor`.

        Solo para estudios: en una academia responde `wrong_vertical`. Un parámetro que la ruta no
        declara responde `validation_failed` con `unknown_parameter`.




## OpenAPI

````yaml /estudios/openapi.yaml get /sessions
openapi: 3.1.0
info:
  title: API de Craqui
  version: '2026-12-01'
  summary: Conecta tu web o tu sistema a tu estudio o academia en Craqui.
  description: >
    API REST de Craqui. Cada clave pertenece a un solo negocio (un estudio o una
    academia) y todo lo

    que devuelve es de ese negocio.


    - **Autenticación:** `Authorization: Bearer <clave>`. Las claves se crean en
    Configuración →
      Integraciones. Una app de terceros usa, en lugar de una clave, el access token (`crq_oat_…`) que recibe
      cuando el propietario de un negocio la conecta (OAuth 2.1): vale para ese negocio y los permisos que el
      propietario aceptó. Una clave `crq_live_` usa los datos reales del negocio; una `crq_test_` usa su
      estudio de prueba: la misma configuración (sedes, clases, packs, planes) con clientes y
      reservas de ejemplo, que no le escribe a nadie. La URL es la misma: el entorno lo decide la
      clave. Todo objeto dice en `livemode` de cuál de los dos viene.
    - **Versión:** cada clave queda fijada a la versión vigente cuando se creó.
    El header
      `Craqui-Version` la sobrescribe por pedido, y la respuesta siempre dice cuál se usó.
    - **Errores:** `application/problem+json` (RFC 9457), con un `code` estable
    para programar y un
      `request_id` para buscar el pedido en tu panel.
    - **Montos:** enteros en `amount_cents` (siempre ×100) junto con la moneda
    ISO 4217.

    - **Fechas y horas:** instantes en RFC 3339 con el offset del negocio;
    fechas sin hora como
      `YYYY-MM-DD` en la fecha local del negocio.
  contact:
    name: Craqui
    url: https://craqui.com
servers:
  - url: https://api.craqui.com/v1
    description: Producción
security:
  - bearerAuth: []
tags:
  - name: business
    description: El negocio al que pertenece la clave (un estudio o una academia).
  - name: booking_policy
    description: Las reglas de reserva del estudio. Solo estudios.
  - name: centers
    description: Las sedes del estudio. Solo estudios.
  - name: rooms
    description: Los salones de cada sede. Solo estudios.
  - name: teachers
    description: Quienes dan clases en el estudio. Solo estudios.
  - name: courses
    description: Las disciplinas del estudio (Yoga, Pilates…). Solo estudios.
  - name: classes
    description: Las clases con su horario semanal. Solo estudios.
  - name: sessions
    description: El horario del estudio, sesión por sesión, con sus lugares. Solo estudios.
  - name: clients
    description: >-
      Los clientes del estudio, con el contacto separado en su propio permiso.
      Solo estudios.
  - name: bookings
    description: Las reservas de las sesiones. Solo estudios.
  - name: credit_packs
    description: Los packs de créditos que vende el estudio. Solo estudios.
  - name: membership_plans
    description: Los planes de membresía que vende el estudio. Solo estudios.
  - name: intro_offers
    description: Las ofertas de bienvenida que vende el estudio. Solo estudios.
  - name: credits
    description: Los créditos de los clientes, sus lotes y sus movimientos. Solo estudios.
  - name: memberships
    description: Las membresías de los clientes y sus congelamientos. Solo estudios.
  - name: fees
    description: Las cuotas que el estudio le cobra a cada cliente. Solo estudios.
  - name: payments
    description: Los pagos de las cuotas. Solo estudios.
  - name: refunds
    description: Los reembolsos de los pagos. Solo estudios.
  - name: events
    description: >
      Lo que cambió en el estudio en los últimos 30 días, para enterarte sin
      consultar cada lista. Solo

      estudios.
  - name: webhook_endpoints
    description: >
      Las URLs a las que Craqui le avisa cada vez que algo cambia en el estudio,
      firmado y con reintentos. Solo

      estudios y solo con una clave `crq_live_`.
paths:
  /sessions:
    get:
      tags:
        - sessions
      summary: Listar sesiones
      description: >
        El horario del estudio: las sesiones de sus clases entre dos fechas
        locales, en orden cronológico,

        con quién las da (con la suplencia aplicada) y sus lugares. Las
        canceladas y las de días cerrados no

        vienen, salvo con `include_cancelled=true`.


        `local_date[gte]` y `local_date[lte]` son obligatorios: 31 días como
        máximo, y 14 con

        `has_capacity` (`range_too_long`).

                Paginada por cursor: para sincronizar todo, pide `limit=100` y sigue `next_cursor`.

                Solo para estudios: en una academia responde `wrong_vertical`. Un parámetro que la ruta no
                declara responde `validation_failed` con `unknown_parameter`.
      operationId: listSessions
      parameters:
        - $ref: '#/components/parameters/CraquiVersion'
        - $ref: '#/components/parameters/LocalDateFrom'
        - $ref: '#/components/parameters/LocalDateTo'
        - $ref: '#/components/parameters/CenterIdFilter'
        - name: room_id
          in: query
          required: false
          description: Solo las sesiones de este salón.
          schema:
            $ref: '#/components/schemas/RoomId'
        - $ref: '#/components/parameters/CourseIdFilter'
        - name: class_id
          in: query
          required: false
          description: Solo las sesiones de esta clase.
          schema:
            $ref: '#/components/schemas/ClassId'
        - name: teacher_id
          in: query
          required: false
          description: >-
            Solo las sesiones que da este instructor (con la suplencia aplicada,
            igual que `teacher_id`).
          schema:
            $ref: '#/components/schemas/TeacherId'
        - name: has_capacity
          in: query
          required: false
          description: >-
            `true`, solo las sesiones con lugar; `false`, solo las llenas o que
            no se dan. Con este filtro el rango es de 14 días como máximo.
          schema:
            type: boolean
        - name: include_cancelled
          in: query
          required: false
          description: >-
            `true` suma las sesiones canceladas y las de días que el estudio
            cerró.
          schema:
            type: boolean
        - $ref: '#/components/parameters/Limit'
        - $ref: '#/components/parameters/StartingAfter'
      responses:
        '200':
          description: OK.
          headers:
            Request-Id:
              $ref: '#/components/headers/RequestId'
            Craqui-Version:
              $ref: '#/components/headers/CraquiVersion'
            RateLimit:
              $ref: '#/components/headers/RateLimit'
            RateLimit-Policy:
              $ref: '#/components/headers/RateLimitPolicy'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SessionList'
              example:
                object: list
                data:
                  - id: ses_01jwjv0tty1d2becjf2qn4rnen
                    object: session
                    livemode: true
                    class_id: cls_01jayrnm27ycx4v65zqy50dw1m
                    course_id: crs_01jc38f2tyy9nr9zt12gjvr4z2
                    center_id: ctr_01j65pdnq74qvnh0953pzvtczg
                    room_id: room_01j2nmepjqt1yzqwytr979e6y8
                    teacher_id: tch_01j1tqm7sqp83vjt0knab671mx
                    starts_at: '2026-12-01T08:00:00-03:00'
                    ends_at: '2026-12-01T08:50:00-03:00'
                    local_date: '2026-12-01'
                    local_start_time: '08:00'
                    local_end_time: '08:50'
                    time_zone: America/Montevideo
                    status: scheduled
                    capacity: 8
                    booked_count: 6
                    waitlist_count: 0
                    available_spots: 2
                    created_at: '2026-11-03T03:00:00-03:00'
                    updated_at: '2026-11-03T03:00:00-03:00'
                  - 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: scheduled
                    capacity: 20
                    booked_count: 20
                    waitlist_count: 2
                    available_spots: 0
                    created_at: '2026-11-04T03:00:00-03:00'
                    updated_at: '2026-11-04T03:00:00-03:00'
                  - id: ses_01j2d1vb84pqs90137c12qvz8q
                    object: session
                    livemode: true
                    class_id: cls_01jayrnm27ycx4v65zqy50dw1m
                    course_id: crs_01jc38f2tyy9nr9zt12gjvr4z2
                    center_id: ctr_01j65pdnq74qvnh0953pzvtczg
                    room_id: room_01j2nmepjqt1yzqwytr979e6y8
                    teacher_id: tch_01j1tqm7sqp83vjt0knab671mx
                    starts_at: '2026-12-03T08:00:00-03:00'
                    ends_at: '2026-12-03T08:50:00-03:00'
                    local_date: '2026-12-03'
                    local_start_time: '08:00'
                    local_end_time: '08:50'
                    time_zone: America/Montevideo
                    status: scheduled
                    capacity: 8
                    booked_count: 3
                    waitlist_count: 0
                    available_spots: 5
                    created_at: '2026-11-05T03:00:00-03:00'
                    updated_at: '2026-11-05T03:00:00-03:00'
                has_more: true
                next_cursor: eyJrIjoiMjAyNi0xMi0wM1QwODowMDowMC0wMzowMCJ9
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          $ref: '#/components/responses/Conflict'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          $ref: '#/components/responses/InternalError'
      security:
        - bearerAuth: []
        - oauth2:
            - sessions:read
components:
  parameters:
    CraquiVersion:
      name: Craqui-Version
      in: header
      required: false
      description: >
        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ó.
      schema:
        type: string
        pattern: ^\d{4}-\d{2}-\d{2}$
        examples:
          - '2026-12-01'
    LocalDateFrom:
      name: local_date[gte]
      in: query
      required: true
      description: La primera fecha local, incluida.
      schema:
        $ref: '#/components/schemas/LocalDate'
    LocalDateTo:
      name: local_date[lte]
      in: query
      required: true
      description: >
        La última fecha local, incluida. El rango es de 31 días como máximo, y
        de 14 con `has_capacity`;

        más largo responde `validation_failed` con `range_too_long`.
      schema:
        $ref: '#/components/schemas/LocalDate'
    CenterIdFilter:
      name: center_id
      in: query
      required: false
      description: Solo lo de esta sede.
      schema:
        $ref: '#/components/schemas/CenterId'
    CourseIdFilter:
      name: course_id
      in: query
      required: false
      description: Solo lo de esta disciplina.
      schema:
        $ref: '#/components/schemas/CourseId'
    Limit:
      name: limit
      in: query
      required: false
      description: Cuántos elementos traer, de 1 a 100.
      schema:
        type: integer
        minimum: 1
        maximum: 100
        default: 20
    StartingAfter:
      name: starting_after
      in: query
      required: false
      schema:
        type: string
      description: >
        El `next_cursor` de la página anterior. Sirve solo para la misma ruta
        con los mismos filtros: con

        otros, la respuesta es `invalid_cursor`.
  schemas:
    RoomId:
      type: string
      description: Id de un salón.
      pattern: ^room_[0-7][0-9a-hjkmnp-tv-z]{25}$
      examples:
        - room_01jhweg897s9npa0tasfgt6a65
    ClassId:
      type: string
      description: Id de una clase (el grupo con su horario semanal).
      pattern: ^cls_[0-7][0-9a-hjkmnp-tv-z]{25}$
      examples:
        - cls_01jryg07jeazdbx61dnx96ckmv
    TeacherId:
      type: string
      description: Id de un instructor.
      pattern: ^tch_[0-7][0-9a-hjkmnp-tv-z]{25}$
      examples:
        - tch_01jmwqh91chk154n8xwnaw5ynd
    SessionList:
      allOf:
        - $ref: '#/components/schemas/List'
        - type: object
          properties:
            data:
              type: array
              items:
                $ref: '#/components/schemas/Session'
    LocalDate:
      type: string
      format: date
      description: Fecha local del negocio, `YYYY-MM-DD`.
      pattern: ^\d{4}-\d{2}-\d{2}$
      examples:
        - '2026-12-02'
    CenterId:
      type: string
      description: Id de una sede.
      pattern: ^ctr_[0-7][0-9a-hjkmnp-tv-z]{25}$
      examples:
        - ctr_01j65pdnq74qvnh0953pzvtczg
    CourseId:
      type: string
      description: Id de una disciplina.
      pattern: ^crs_[0-7][0-9a-hjkmnp-tv-z]{25}$
      examples:
        - crs_01jff81dk7rxtacmye5nanfp0h
    List:
      type: object
      required:
        - object
        - data
        - has_more
        - next_cursor
      properties:
        object:
          type: string
          const: list
        data:
          type: array
          items: {}
        has_more:
          type: boolean
          description: Si hay más elementos después de esta página.
        next_cursor:
          type:
            - string
            - 'null'
          description: >-
            Pásalo en `starting_after` para pedir la página siguiente. `null` si
            no hay más.
    Session:
      type: object
      description: >
        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.
      required:
        - id
        - object
        - livemode
        - class_id
        - course_id
        - center_id
        - room_id
        - teacher_id
        - starts_at
        - ends_at
        - local_date
        - local_start_time
        - local_end_time
        - time_zone
        - status
        - capacity
        - booked_count
        - waitlist_count
        - available_spots
        - created_at
        - updated_at
      properties:
        id:
          $ref: '#/components/schemas/SessionId'
        object:
          type: string
          const: session
        livemode:
          type: boolean
          description: >-
            `false` si el objeto es de tu estudio de prueba (claves
            `crq_test_`); `true` con claves `crq_live_`.
        class_id:
          $ref: '#/components/schemas/ClassId'
        course_id:
          $ref: '#/components/schemas/CourseId'
        center_id:
          oneOf:
            - $ref: '#/components/schemas/CenterId'
            - type: 'null'
        room_id:
          description: El salón de esta sesión, si tiene uno asignado.
          oneOf:
            - $ref: '#/components/schemas/RoomId'
            - type: 'null'
        teacher_id:
          description: >
            Quien da esta sesión, con la suplencia aplicada (igual que el
            calendario del estudio). `null`

            si no tiene instructor asignado.
          oneOf:
            - $ref: '#/components/schemas/TeacherId'
            - type: 'null'
        starts_at:
          $ref: '#/components/schemas/Instant'
          description: >
            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.
        ends_at:
          $ref: '#/components/schemas/Instant'
          description: El fin. Una clase que cruza la medianoche termina al día siguiente.
        local_date:
          $ref: '#/components/schemas/LocalDate'
        local_start_time:
          $ref: '#/components/schemas/LocalTime'
        local_end_time:
          $ref: '#/components/schemas/LocalTime'
        time_zone:
          type:
            - string
            - 'null'
          description: >-
            La zona horaria del estudio (IANA). `null` si el estudio no eligió
            una; los instantes salen en `+00:00`.
          examples:
            - America/Montevideo
        status:
          type: string
          description: >
            `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.
          enum:
            - scheduled
            - cancelled
            - studio_closed
          x-extensible-enum: true
        capacity:
          type:
            - integer
            - 'null'
          description: El cupo de la sesión. `null` si la clase no tiene cupo.
        booked_count:
          type: integer
          description: >
            Los lugares tomados: reservas confirmadas, asistidas y ausentes
            hasta que la sesión empieza. Es

            la misma cuenta que usa Craqui al reservar.
          minimum: 0
        waitlist_count:
          type: integer
          description: Cuántas personas esperan en la lista de espera.
          minimum: 0
        available_spots:
          type:
            - integer
            - 'null'
          description: >-
            `capacity - booked_count`, nunca menos de 0. `null` si la clase no
            tiene cupo.
          minimum: 0
        created_at:
          $ref: '#/components/schemas/Instant'
        updated_at:
          $ref: '#/components/schemas/Instant'
    Problem:
      type: object
      description: >
        Un error. Programa contra `code`, que no cambia; `title` y `detail` son
        para mostrarle a una

        persona y pueden cambiar de redacción.
      required:
        - type
        - title
        - status
        - code
        - request_id
      properties:
        type:
          type: string
          format: uri
          description: URL de la página de la documentación de este error.
          examples:
            - https://docs.craqui.com/errors/invalid_api_key
        title:
          type: string
          description: Resumen corto, en español.
          examples:
            - La clave no es válida
        status:
          type: integer
          description: El mismo código HTTP de la respuesta.
          examples:
            - 401
        code:
          type: string
          description: >
            Código estable del error. La lista puede crecer: trata un `code` que
            no conoces como un

            error genérico de su `status`.
          examples:
            - invalid_api_key
        detail:
          type: string
          description: Qué pasó y qué hacer, en español.
          examples:
            - >-
              Revisa que copiaste la clave completa, incluido el prefijo
              (crq_live_ o crq_test_).
        request_id:
          type: string
          pattern: ^req_[0-9a-hjkmnp-tv-z]{26}$
          description: >-
            Identificador del pedido. Búscalo en Configuración → Integraciones →
            Actividad de la API.
          examples:
            - req_01hzx8m4k2a7d9q3f5w6y8z0bc
        doc_url:
          type: string
          format: uri
          description: >-
            Igual a `type`, por compatibilidad con clientes que buscan este
            campo.
        required_scope:
          type: string
          description: >-
            Solo en `scope_required` y `event_type_not_permitted`. El permiso
            que le falta a la clave.
          examples:
            - business:read
        errors:
          type: array
          description: Solo en errores de validación. Un elemento por campo con problemas.
          items:
            $ref: '#/components/schemas/FieldError'
        current_price:
          $ref: '#/components/schemas/Money'
          description: >-
            Solo en `price_changed`. El precio de hoy, en centésimos y con su
            moneda.
        expected_amount:
          $ref: '#/components/schemas/Money'
          description: >-
            Solo en `amount_mismatch`. El saldo de hoy de la cuota, en
            centésimos y con su moneda.
        amount_at_stake:
          $ref: '#/components/schemas/Money'
          description: >-
            Solo en `advance_payment_choice_required`. Lo que falta cobrar del
            pago por adelantado.
        existing_membership_id:
          $ref: '#/components/schemas/MembershipId'
          description: >
            Solo en `active_membership_exists`, `membership_suspended`,
            `membership_paused` y `membership_scheduled` al

            asignar una membresía: la que el cliente ya tiene.
        booking_ids:
          type: array
          description: >-
            Solo en `bookings_in_freeze_window` y `bookings_changed`. Las
            reservas en esas fechas.
          items:
            $ref: '#/components/schemas/BookingId'
    SessionId:
      type: string
      description: Id de una sesión (una fecha de una clase).
      pattern: ^ses_[0-7][0-9a-hjkmnp-tv-z]{25}$
      examples:
        - ses_01jnb07m4yxxe0s687jf750tkv
    Instant:
      type: string
      format: date-time
      description: Instante en RFC 3339 con el offset del negocio en ese momento.
      examples:
        - '2026-12-02T19:00:00-03:00'
    LocalTime:
      type: string
      description: Hora local del negocio, `HH:MM` (24 horas).
      pattern: ^\d{2}:\d{2}$
      examples:
        - '19:00'
    FieldError:
      type: object
      required:
        - field
        - code
      properties:
        field:
          type: string
          description: El campo, como lo mandaste (por ejemplo `limit`).
          examples:
            - limit
        code:
          type: string
          description: Qué tiene mal el campo.
          examples:
            - invalid_limit
        detail:
          type: string
          description: Explicación en español.
    Money:
      type: object
      required:
        - amount_cents
        - currency
      properties:
        amount_cents:
          type: integer
          description: >
            El monto multiplicado por 100. `250000` con `UYU` es $ 2.500,00. Un
            entero: `250000.5` o `"250000"` es

            `validation_failed` (`250000.0` es el mismo número que `250000`).
          examples:
            - 250000
        currency:
          $ref: '#/components/schemas/CurrencyCode'
    MembershipId:
      type: string
      description: Id de una membresía de un cliente.
      pattern: ^mem_[0-7][0-9a-hjkmnp-tv-z]{25}$
      examples:
        - mem_01j1q27t44qvr6v2s50cv4rbvq
    BookingId:
      type: string
      description: Id de una reserva.
      pattern: ^bkg_[0-7][0-9a-hjkmnp-tv-z]{25}$
      examples:
        - bkg_01jx9eak0437zdf0yw0atg7g0r
    CurrencyCode:
      type: string
      description: Moneda ISO 4217, en mayúsculas.
      pattern: ^[A-Z]{3}$
      examples:
        - UYU
  headers:
    RequestId:
      description: Identificador del pedido. Aparece también en el cuerpo de los errores.
      schema:
        type: string
        pattern: ^req_[0-9a-hjkmnp-tv-z]{26}$
    CraquiVersion:
      description: La versión de la API con la que se respondió.
      schema:
        type: string
        pattern: ^\d{4}-\d{2}-\d{2}$
    RateLimit:
      description: >-
        Pedidos que quedan en la ventana actual y segundos hasta que se renueva
        (draft IETF httpapi-ratelimit-headers).
      schema:
        type: string
        examples:
          - '"read";r=97;t=42'
    RateLimitPolicy:
      description: Límite de la clave por ventana (draft IETF httpapi-ratelimit-headers).
      schema:
        type: string
        examples:
          - '"read";q=100;w=60'
    RetryAfter:
      description: Segundos que hay que esperar antes de reintentar.
      schema:
        type: integer
        minimum: 0
  responses:
    BadRequest:
      description: >
        El pedido está mal formado. Códigos posibles: `invalid_api_version`,
        `idempotency_key_required`,

        `validation_failed` (con un elemento de `errors` por parámetro:
        `unknown_parameter`,

        `invalid_prefix`, `invalid_id`, `invalid_date`, `invalid_boolean`,
        `invalid_enum`,

        `invalid_limit`, `duplicate_parameter`, `expand_not_supported`…) e
        `invalid_cursor` (un

        `starting_after` de otra búsqueda: repite la primera página con los
        mismos filtros). En las URLs de

        avisos, `webhook_url_invalid` (en `errors`, la causa: `not_https`,
        `port_not_allowed`,

        `credentials_in_url`, `ip_literal`, `internal_hostname`,
        `private_address`, `craqui_host` o `too_long`).

        Al cancelar una sesión, `notify_not_supported` (esa escritura no lleva
        `notify`: siempre avisa); también al

        revocar un pack y al congelar o descongelar una membresía (no le avisan
        nada al cliente). En las escrituras de

        plata, `fee_decision_required` y `current_fee_choice_required` (la API
        no decide sobre plata por ti).

        Un token en la URL o en un cuerpo de formulario responde
        `invalid_request`: va solo en el header

        `Authorization`. El detalle de un error nunca repite el valor que
        mandaste.
      headers:
        Request-Id:
          $ref: '#/components/headers/RequestId'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
    Unauthorized:
      description: >
        Falta la clave o no sirve. Códigos posibles: `missing_api_key`,
        `invalid_api_key`,

        `revoked_api_key`, `expired_api_key`, `legacy_api_key`. Con el token de
        una app: `invalid_access_token` (no

        es válido o venció: pide otro con el refresh token) y
        `app_connection_revoked` (el propietario desconectó la

        app); los dos llevan el header `WWW-Authenticate: Bearer
        error="invalid_token"`.
      headers:
        Request-Id:
          $ref: '#/components/headers/RequestId'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
          examples:
            revoked:
              value:
                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
    Forbidden:
      description: >
        La clave es válida pero no puede hacer esto. Códigos posibles:
        `scope_required`,

        `plan_required`, `api_key_suspended`, `browser_not_allowed`,
        `wrong_vertical`,

        `event_type_not_permitted` (eventos de un recurso que la clave no puede
        leer; `required_scope` dice cuál) y

        `write_access_disabled` (en una ruta que crea o cambia datos, si tu
        negocio no tiene habilitada la escritura por

        la API) y `money_writes_not_enabled` (en una ruta de packs, membresías o
        pagos, si tu negocio no tiene

        habilitadas las escrituras de plata). Con el token de una app, además:
        `app_suspended` (Craqui suspendió la

        app) y `app_connection_suspended` (quien conectó la app ya no es
        propietario del negocio).
      headers:
        Request-Id:
          $ref: '#/components/headers/RequestId'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
    Conflict:
      description: >
        Solo con una clave `crq_test_`: tu estudio de prueba no está listo.
        Código

        `sandbox_unavailable`. Restablece tus datos de prueba en Configuración →
        Integraciones y vuelve

        a intentar. Una clave de prueba nunca responde con los datos reales del
        negocio. En los pedidos que

        crean o modifican algo, también `idempotency_in_progress` (el mismo
        pedido todavía se está procesando) y,

        al crear una URL de avisos, `webhook_endpoint_limit_reached` (ya hay
        10). En una ruta que crea o cambia datos

        del estudio, además, sus reglas no dejan hacerlo: la descripción de cada
        ruta lista sus códigos.
      headers:
        Request-Id:
          $ref: '#/components/headers/RequestId'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
          examples:
            sandbox_unavailable:
              value:
                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
    TooManyRequests:
      description: >-
        Se pasó el límite de pedidos por minuto de la clave. Código
        `rate_limited`.
      headers:
        Request-Id:
          $ref: '#/components/headers/RequestId'
        Retry-After:
          $ref: '#/components/headers/RetryAfter'
        RateLimit:
          $ref: '#/components/headers/RateLimit'
        RateLimit-Policy:
          $ref: '#/components/headers/RateLimitPolicy'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
    InternalError:
      description: >-
        Falló algo de nuestro lado. Código `internal_error`. Reintenta; si
        sigue, escríbenos con el `request_id`.
      headers:
        Request-Id:
          $ref: '#/components/headers/RequestId'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: crq_live_sk_… / crq_live_rk_…
      description: >
        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`.
    oauth2:
      type: oauth2
      description: >
        Una app de terceros conectada a un negocio por su propietario (OAuth
        2.1, Authorization Code con PKCE). El

        access token (`crq_oat_…`) vale 1 hora, va solo en el header
        `Authorization: Bearer` y es de un solo negocio.

        Una app nunca recibe `notifications:suppress` ni `webhooks:manage`. Ver
        https://docs.craqui.com/apps.
      flows:
        authorizationCode:
          authorizationUrl: https://www.craqui.com/oauth/authorize
          tokenUrl: https://api.craqui.com/oauth/token
          refreshUrl: https://api.craqui.com/oauth/token
          scopes:
            business:read: Ver los datos básicos del negocio (siempre incluido).
            centers:read: Ver las sedes.
            rooms:read: Ver los salones.
            teachers:read: Ver a quienes dan clases.
            courses:read: Ver las disciplinas.
            classes:read: Ver las clases y su horario.
            sessions:read: Ver el horario, sesión por sesión.
            sessions:write: Cancelar sesiones.
            clients:read: Ver los clientes.
            clients.pii:read: Ver el email y el teléfono de los clientes.
            clients:write: Crear, cambiar, dar de baja y reactivar clientes.
            bookings:read: Ver las reservas.
            bookings:write: Reservar, cancelar reservas y marcar asistencia.
            credits:read: Ver los créditos de los clientes.
            credits:write: Asignar y revocar packs de créditos.
            memberships:read: Ver las membresías.
            memberships:write: Asignar, cancelar, congelar y descongelar membresías.
            fees:read: Ver las cuotas.
            payments:read: Ver los pagos.
            refunds:read: Ver los reembolsos.
            payments:write: Registrar pagos.
            events:read: Ver la lista de cambios recientes.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.