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

# Scan an attendee

> Validate an attendee’s admission and submit a check-in through the developer API.



## OpenAPI

````yaml api-reference/openapi.json POST /scan
openapi: 3.0.3
info:
  title: TicketSpot Developer API
  version: 2.1.0
  description: >-
    Manage events and attendees for the site associated with your API key.
    Developer API access requires a paid Business, Business+ or Platform plan.
    Free plans, trials and ticket packs do not grant API access. Eligibility is
    checked on every request using the billing plan resolver and its existing
    cache invalidation.


    Create a key in the dashboard under Settings > API Keys. Send Authorization:
    Bearer <api_key>. Keys use ts-{uuid}-{secret}; the secret is shown once and
    stored as a hash. Available scopes: events:read, events:create,
    events:update, attendees:read, attendees:scan.


    Rate limits are shared across application instances: 120 requests/minute per
    key, 600 requests/minute per site, and 300 requests/minute per IP before
    authentication. Responses include RateLimit-Limit, RateLimit-Remaining and
    RateLimit-Reset (seconds until reset). Exceeding a limit returns 429 with
    Retry-After. Redis outages return 503. Maximum API body size is 8 MiB.


    Event and attendee lists use cursor pagination: limit defaults to 25
    (maximum 100), and pagination.next_cursor is null at the end. Attendee
    search matches case-insensitive prefixes of names and email addresses.
    Scanning ordinary tickets queues the existing check-in task; a 202 means
    accepted for processing, and the attendee record may update shortly
    afterward. Invalid or duplicate scans return 409.
servers:
  - url: https://ticketspotapp.com/api/api/v2
    description: Production API
security:
  - bearerAuth: []
paths:
  /scan:
    post:
      summary: Scan an attendee
      description: >-
        Accepts an attendee ID. Requires an attending or checkedIn attendee at
        this key's site. Existing ticket validity, required check-in answers,
        scan limits and membership admission rules are applied. Kiosk print
        tokens and private order details are not returned.
      operationId: scanAttendee
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ScanRequest'
      responses:
        '202':
          description: Scan accepted.
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  accepted:
                    type: boolean
                  attendee:
                    $ref: '#/components/schemas/Attendee'
                  ticket_validity:
                    $ref: '#/components/schemas/TicketValidity'
        '400':
          $ref: '#/components/responses/Error400'
        '401':
          $ref: '#/components/responses/Error401'
        '403':
          $ref: '#/components/responses/Error403'
        '404':
          $ref: '#/components/responses/Error404'
        '409':
          description: Scan rejected or conflicts with attendee state.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - type: object
                    properties:
                      success:
                        type: boolean
                      accepted:
                        type: boolean
                      attendee:
                        $ref: '#/components/schemas/Attendee'
                      ticket_validity:
                        $ref: '#/components/schemas/TicketValidity'
        '413':
          $ref: '#/components/responses/Error413'
        '429':
          $ref: '#/components/responses/Error429'
        '500':
          $ref: '#/components/responses/Error500'
        '503':
          $ref: '#/components/responses/Error503'
components:
  schemas:
    ScanRequest:
      type: object
      properties:
        attendee_id:
          type: string
          example: attendee-uuid
        event_id:
          type: string
          description: Optional expected event ID. The attendee must belong to this event.
        idempotency_key:
          type: string
          pattern: ^[A-Za-z0-9_-]{16,128}$
          description: >-
            Stable request ID for membership admissions. Ordinary ticket scans
            use a shared five-second duplicate guard and do not provide
            long-term idempotency.
      required:
        - attendee_id
      additionalProperties: false
    Attendee:
      type: object
      properties:
        id:
          type: string
        event_id:
          type: string
        first_name:
          type: string
        last_name:
          type: string
        email:
          type: string
        status:
          type: string
        ticket_id:
          type: string
          nullable: true
        checkin_scan_count:
          type: integer
        created_at:
          type: string
          format: date-time
    TicketValidity:
      type: object
      properties:
        isValid:
          type: boolean
        reason:
          type: string
        reason_description:
          type: string
    Error:
      type: object
      properties:
        error:
          type: string
        code:
          type: string
        message:
          type: string
  responses:
    Error400:
      description: Invalid request.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Error401:
      description: Missing, invalid, expired or revoked API key.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Error403:
      description: Paid Business plan required, or API key is missing the operation scope.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Error404:
      description: Resource not found on this site.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Error413:
      description: Request body exceeds 8 MiB.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Error429:
      description: Shared API rate limit exceeded.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
      headers:
        Retry-After:
          description: Seconds to wait before retrying.
          schema:
            type: integer
    Error500:
      description: Request could not be completed.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Error503:
      description: Rate limiting or scan protection temporarily unavailable.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
      headers:
        Retry-After:
          description: Seconds to wait before retrying.
          schema:
            type: integer
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: TicketSpot API key
      description: ts-{uuid}-{secret}. Every key requires its independent secret.

````

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