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

# Validate a wristband's access to a zone

> Checks whether a wristband may enter a given zone, and records the scan.

**Denying is not an error**: the response is always `200` with `allowed: true|false` and the reason. A `403` would mean your API key lacks permission, which is a different matter.



## OpenAPI

````yaml /openapi.en.json post /access-checks
openapi: 3.1.0
info:
  title: VENTRY API
  version: 1.0.0
  description: >-
    **VENTRY**'s public API for external integrators.


    It lets you push tickets from a ticketing platform, accredit attendees from
    your

    own application and read the state of the event in real time.


    ## Authentication


    Every call carries an API key in the `Authorization` header:


    ```

    Authorization: Bearer vk_live_8Kq2...

    ```


    The key is issued from the VENTRY dashboard and **shown only once**. If it
    is

    lost, a new one must be issued. Keys requesting write scopes are created
    disabled

    and need an event administrator to enable them by hand.


    ## One deployment, one event


    Each VENTRY installation corresponds to **a single event**. The API key
    already

    determines which event you are talking about, which is why no endpoint takes
    an

    event identifier. A key may additionally be restricted to certain ticket
    types or

    certain days: anything outside that scope behaves as if it did not exist.


    ## Conventions


    - **Amounts**: integers in **cents**. `1250` is €12.50. The currency is in
    `GET /event`.

    - **Dates**: ISO 8601 in UTC. The event's time zone is in `GET /event`.

    - **Identifiers**: 24-character hexadecimal strings.

    - **Fields**: `snake_case`.


    ### `occurred_at` versus `created_at`


    VENTRY terminals keep charging without connectivity and sync afterwards.
    That is

    why sales and top-ups carry two timestamps: `occurred_at` is when it
    actually

    happened and `created_at` when it reached the server. **To group by time or

    reconcile takings you must always use `occurred_at`**; a sale made at 22:00
    and

    synced at 02:00 belongs to Friday night, not Saturday's.


    ## Pagination


    Lists return `{ object: "list", data, has_more, next_cursor }`. To get the
    next

    page, repeat the call with `starting_after=<next_cursor>`. There are no page

    numbers: the cursor stays stable even while records are being created as you

    walk the list.


    To sync incrementally, combine `updated_since` with the cursor.


    ## Idempotency


    Writes require the `Idempotency-Key` header with a UUID generated by the
    client.

    Repeating the same call with the same key returns the original response
    without

    executing anything again, so a retry after a network failure never
    duplicates a

    ticket or a top-up. Reusing the key with a different body returns

    `422 idempotency_key_reused`.


    ## Limits


    By default **120 requests per minute** per key, and **20 per minute** for
    writes.

    Every response carries `x-ratelimit-remaining` and, once exhausted,

    `retry-after` with the seconds left.


    ## Errors


    Every error shares the same shape and carries a `request_id` worth logging:
    with

    it, VENTRY support can find your exact request.
  contact:
    name: Soporte VENTRY
    url: https://ventry.es
servers:
  - url: http://localhost:3000/v1
    description: Event server
security:
  - apiKey: []
tags:
  - name: Event
    description: >-
      Event configuration: days, zones and ticket types. Read this first to map
      your own catalogue against VENTRY's.
  - name: Tickets
    description: Create, read and cancel tickets. The API's main use case.
  - name: Access control
    description: >-
      Door accreditation and zone control. Requires write scopes activated
      manually.
  - name: Cashless
    description: Wristband balances, purchases and top-ups. All amounts in cents.
  - name: Reports
    description: Sales aggregates, consistent with the dashboard's daily closeout.
  - name: Meta
    description: Credential checks and documentation.
paths:
  /access-checks:
    post:
      tags:
        - Access control
      summary: Validate a wristband's access to a zone
      description: >-
        Checks whether a wristband may enter a given zone, and records the scan.


        **Denying is not an error**: the response is always `200` with `allowed:
        true|false` and the reason. A `403` would mean your API key lacks
        permission, which is a different matter.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - wristband_code
                - zone
              properties:
                wristband_code:
                  type: string
                  description: NFC identifier read from the wristband.
                zone:
                  type: string
                  description: Zone id from `GET /zones`.
      responses:
        '200':
          description: Result of the access check.
          content:
            application/json:
              schema:
                type: object
                description: Result of the access check.
                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: Malformed request.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Missing, invalid or expired API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: The API key lacks the required scope.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: The given zone does not exist.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: Rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Internal error.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
components:
  schemas:
    Error:
      type: object
      description: >-
        Every API error shares this shape. Branch on `code`, which is stable;
        `message` may be reworded.
      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: Request field that caused the error, where applicable.
            request_id:
              type: string
              description: Request identifier. Quote it when contacting support.
              example: req_9f2c1a4e7b304d51
          required:
            - type
            - code
            - message
            - request_id
      required:
        - error
  securitySchemes:
    apiKey:
      type: http
      scheme: bearer
      bearerFormat: API key
      description: >-
        Integrator API key, issued from the VENTRY dashboard. Format
        `vk_live_...` in production and `vk_test_...` in test environments.

````