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

# Validar el acceso de una pulsera a una zona

> Comprueba si una pulsera puede entrar en una zona concreta y deja constancia del escaneo.

**Denegar no es un error**: la respuesta es siempre `200` con `allowed: true|false` y el motivo. Un `403` significaría que tu API key no tiene permiso, que es otra cosa.



## OpenAPI

````yaml /openapi.json post /access-checks
openapi: 3.1.0
info:
  title: VENTRY API
  version: 1.0.0
  description: >-
    API pública de **VENTRY** para integradores externos.


    Permite volcar entradas desde una plataforma de ticketing, acreditar
    asistentes

    desde una aplicación propia y consultar el estado del evento en tiempo real.


    ## Autenticación


    Todas las llamadas viajan con una API key en la cabecera `Authorization`:


    ```

    Authorization: Bearer vk_live_8Kq2...

    ```


    La clave se genera desde el panel de VENTRY y **se muestra una sola vez**.
    Si se

    pierde, hay que emitir otra. Las claves que piden permisos de escritura
    nacen

    desactivadas y necesitan que un administrador del evento las habilite a
    mano.


    ## Un despliegue, un evento


    Cada instalación de VENTRY corresponde a **un único evento**. La API key ya

    determina de qué evento se está hablando, por eso ningún endpoint pide un

    identificador de evento. Una clave puede además estar limitada a ciertos
    tipos

    de entrada o a ciertos días: lo que quede fuera de ese ámbito se comporta
    como

    si no existiera.


    ## Convenciones


    - **Importes**: enteros en **céntimos**. `1250` son 12,50 €. La moneda está
    en `GET /event`.

    - **Fechas**: ISO 8601 en UTC. El huso horario del evento está en `GET
    /event`.

    - **Identificadores**: cadenas de 24 caracteres hexadecimales.

    - **Campos**: `snake_case`.


    ### `occurred_at` frente a `created_at`


    Los terminales de VENTRY siguen cobrando sin cobertura y sincronizan
    después.

    Por eso las ventas y recargas llevan dos marcas: `occurred_at` es cuándo
    pasó

    de verdad y `created_at` cuándo llegó al servidor. **Para agrupar por tiempo
    o

    cuadrar caja hay que usar siempre `occurred_at`**; una venta de las 22:00

    sincronizada a las 02:00 pertenece a la noche del viernes, no a la del
    sábado.


    ## Paginación


    Los listados devuelven `{ object: "list", data, has_more, next_cursor }`.
    Para

    la siguiente página se repite la llamada con `starting_after=<next_cursor>`.

    No hay números de página: el cursor es estable aunque se sigan creando
    registros

    mientras se recorre el listado.


    Para sincronizar de forma incremental, combina `updated_since` con el
    cursor.


    ## Idempotencia


    Las escrituras exigen la cabecera `Idempotency-Key` con un UUID generado por

    el cliente. Repetir la misma llamada con la misma clave devuelve la
    respuesta

    original sin volver a ejecutar nada, así que un reintento tras un fallo de
    red

    nunca duplica una entrada ni una recarga. Reutilizar la clave con un cuerpo

    distinto devuelve `422 idempotency_key_reused`.


    ## Límites


    Por defecto **120 peticiones por minuto** y clave, y **20 por minuto** para
    las

    escrituras. Cada respuesta lleva `x-ratelimit-remaining` y, al agotarse,

    `retry-after` con los segundos que faltan.


    ## Errores


    Todos los errores comparten la misma forma y llevan un `request_id` que

    conviene registrar: con él, el soporte de VENTRY encuentra la petición
    exacta.
  contact:
    name: Soporte VENTRY
    url: https://ventry.es
servers:
  - url: http://localhost:3000/v1
    description: Servidor del evento
security:
  - apiKey: []
tags:
  - name: Evento
    description: >-
      Configuración del evento: días, zonas y tipos de entrada. Es lo primero
      que hay que leer para mapear el catálogo propio contra el de VENTRY.
  - name: Entradas
    description: >-
      Alta, consulta y anulación de entradas. El caso de uso principal de la
      API.
  - name: Accesos
    description: >-
      Acreditación en puerta y control de zonas. Requiere permisos de escritura
      activados manualmente.
  - name: Cashless
    description: >-
      Saldo de pulseras, consumiciones y recargas. Todos los importes en
      céntimos.
  - name: Informes
    description: Agregados de venta, coherentes con el cierre de caja del panel.
  - name: Meta
    description: Comprobación de credenciales y documentación.
paths:
  /access-checks:
    post:
      tags:
        - Accesos
      summary: Validar el acceso de una pulsera a una zona
      description: >-
        Comprueba si una pulsera puede entrar en una zona concreta y deja
        constancia del escaneo.


        **Denegar no es un error**: la respuesta es siempre `200` con `allowed:
        true|false` y el motivo. Un `403` significaría que tu API key no tiene
        permiso, que es otra cosa.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - wristband_code
                - zone
              properties:
                wristband_code:
                  type: string
                  description: Identificador NFC leído de la pulsera.
                zone:
                  type: string
                  description: Id de zona de `GET /zones`.
      responses:
        '200':
          description: Resultado de la comprobación de acceso.
          content:
            application/json:
              schema:
                type: object
                description: Resultado de la comprobación de acceso.
                properties:
                  object:
                    type: string
                    enum:
                      - access_check
                  allowed:
                    type: boolean
                  reason:
                    type: string
                  attendee_name:
                    type:
                      - 'null'
                      - string
                  ticket_type:
                    type:
                      - 'null'
                      - string
                  wristband_status:
                    type:
                      - 'null'
                      - string
        '400':
          description: Petición mal formada.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: API key ausente, inválida o caducada.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: La API key no tiene el permiso necesario.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: La zona indicada no existe.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: Se ha superado el límite de peticiones.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Error interno.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
components:
  schemas:
    Error:
      type: object
      description: >-
        Todos los errores de la API comparten esta forma. Ramifica sobre `code`,
        que es estable; `message` puede cambiar de redacción.
      properties:
        error:
          type: object
          properties:
            type:
              type: string
              enum:
                - authentication_error
                - permission_error
                - invalid_request_error
                - not_found_error
                - conflict_error
                - rate_limit_error
                - api_error
            code:
              type: string
              example: ticket_not_found
            message:
              type: string
            param:
              type: string
              description: Campo de la petición que provocó el error, si aplica.
            request_id:
              type: string
              description: Identificador de la petición. Cítalo al contactar con soporte.
              example: req_9f2c1a4e7b304d51
          required:
            - type
            - code
            - message
            - request_id
      required:
        - error
  securitySchemes:
    apiKey:
      type: http
      scheme: bearer
      bearerFormat: API key
      description: >-
        API key del integrador, emitida desde el panel de VENTRY. Formato
        `vk_live_...` en producción y `vk_test_...` en entornos de prueba.

````