openapi: 3.0.3
info:
  title: Autonix Core API
  version: "1.0.0"
  description: |
    Curated public surface for tracked QR codes, scans, and integrations.
    Available on Professional ($99) and Enterprise plans.

    Authenticate with a long-lived API token from Account → API Manager
    (`Authorization: Bearer <token>` or `api_token` query/body).

    Usage is unlimited; protective rate limits apply per token
    (default 120 requests/minute; customizable by Autonix for high-volume accounts).
  contact:
    name: Autonix Support
    url: https://www.autonix.io/contact
servers:
  - url: https://app.autonix.io/api
    description: Production
paths:
  /tracker/qrcode:
    post:
      summary: Create a tracked QR code from a redirect URL
      operationId: createTrackedQr
      tags: [Trackers]
      security:
        - bearerAuth: []
        - apiTokenQuery: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [redirect_url]
              properties:
                redirect_url:
                  type: string
                  format: uri
                  example: https://example.com/landing
                name:
                  type: string
                  description: Optional tracker name (defaults from URL host)
      responses:
        "200":
          description: QR image payload for the new tracker
        "401":
          description: Missing or invalid token
        "429":
          description: Rate limit exceeded
  /tracker:
    get:
      summary: List trackers
      operationId: listTrackers
      tags: [Trackers]
      security:
        - bearerAuth: []
        - apiTokenQuery: []
      responses:
        "200":
          description: Tracker list
    post:
      summary: Create a tracker
      operationId: createTracker
      tags: [Trackers]
      security:
        - bearerAuth: []
        - apiTokenQuery: []
      responses:
        "200":
          description: Created tracker
  /tracker/show/{tracker_id}:
    get:
      summary: Get a tracker
      operationId: getTracker
      tags: [Trackers]
      security:
        - bearerAuth: []
        - apiTokenQuery: []
      parameters:
        - name: tracker_id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Tracker details
  /tracker/analytics/{tracker_id}:
    get:
      summary: Tracker analytics
      operationId: trackerAnalytics
      tags: [Analytics]
      security:
        - bearerAuth: []
        - apiTokenQuery: []
      parameters:
        - name: tracker_id
          in: path
          required: true
          schema:
            type: integer
      responses:
        "200":
          description: "{ totalScans, totalClicks }"
        "403":
          description: Tracker not accessible to this account
  /report/:
    get:
      summary: Aggregated performance report
      description: |
        CRM-friendly aggregates over the caller's accessible trackers.
        Requesting tracker ids outside the account returns 403.
      operationId: getReport
      tags: [Reports]
      security:
        - bearerAuth: []
        - apiTokenQuery: []
      parameters:
        - name: report
          in: query
          required: true
          schema:
            type: string
            enum: [name, type, tag, date, browser, city, country]
        - name: trackers[]
          in: query
          required: false
          schema:
            type: array
            items:
              type: integer
          style: form
          explode: true
        - name: visit_start
          in: query
          schema:
            type: string
            example: "2026-01-01T00:00:00+0000"
        - name: visit_start_end
          in: query
          schema:
            type: string
            example: "2026-01-31T23:59:59+0000"
      responses:
        "200":
          description: "{ data: rows[], meta: { report, tracker_count, visit_start, visit_start_end } }"
        "403":
          description: One or more tracker ids are not accessible
        "422":
          description: Invalid report type or date format
  /report/tag-crosstab:
    get:
      summary: Tag dimension crosstab
      operationId: getTagCrosstab
      tags: [Reports]
      security:
        - bearerAuth: []
        - apiTokenQuery: []
      parameters:
        - name: row
          in: query
          required: true
          schema:
            type: string
            example: region
        - name: col
          in: query
          required: true
          schema:
            type: string
            example: department
        - name: trackers[]
          in: query
          schema:
            type: array
            items:
              type: integer
          style: form
          explode: true
        - name: visit_start
          in: query
          schema:
            type: string
        - name: visit_start_end
          in: query
          schema:
            type: string
      responses:
        "200":
          description: Crosstab matrix under data + meta.tracker_count
        "403":
          description: One or more tracker ids are not accessible
  /dashboard/scansAnalytics:
    get:
      summary: Portfolio scan KPIs
      operationId: scansAnalytics
      tags: [Analytics]
      security:
        - bearerAuth: []
        - apiTokenQuery: []
      parameters:
        - name: trackers
          in: query
          schema:
            type: array
            items:
              type: integer
        - name: dateStart
          in: query
          schema:
            type: string
            format: date
        - name: dateEnd
          in: query
          schema:
            type: string
            format: date
      responses:
        "200":
          description: Period KPIs with optional prior-period comparison
        "403":
          description: One or more tracker ids are not accessible
  /visits/tracker/{tracker_id}:
    get:
      summary: List visits / scans for a tracker
      operationId: listVisits
      tags: [Visits]
      security:
        - bearerAuth: []
        - apiTokenQuery: []
      parameters:
        - name: tracker_id
          in: path
          required: true
          schema:
            type: integer
        - name: visit_start
          in: query
          schema:
            type: string
            example: "2026-01-01T00:00:00+0000"
          description: Window start as Y-m-dTH:i:sO
        - name: visit_start_end
          in: query
          schema:
            type: string
            example: "2026-01-31T23:59:59+0000"
          description: Window end as Y-m-dTH:i:sO
        - name: page
          in: query
          schema:
            type: integer
            minimum: 1
        - name: rows
          in: query
          schema:
            type: integer
            minimum: 1
        - name: search
          in: query
          schema:
            type: string
            minLength: 3
      responses:
        "200":
          description: Visit list (Zapier polling surface)
        "403":
          description: Tracker not accessible
        "422":
          description: Invalid date format or query params
  /visits/tracker/{tracker_id}/download/csv:
    get:
      summary: Download visits CSV for a tracker
      operationId: downloadVisitsCsv
      tags: [Visits]
      security:
        - bearerAuth: []
        - apiTokenQuery: []
      parameters:
        - name: tracker_id
          in: path
          required: true
          schema:
            type: integer
      responses:
        "200":
          description: CSV export
        "403":
          description: Tracker not accessible
  /qrCode:
    post:
      summary: Generate a plain (non-tracked) QR image
      operationId: generatePlainQr
      tags: [QR]
      security:
        - bearerAuth: []
        - apiTokenQuery: []
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required: [type]
              properties:
                type:
                  type: string
                  enum: [url, wifi]
                url:
                  type: string
                  format: uri
                network_name:
                  type: string
                network_password:
                  type: string
                network_encryption:
                  type: string
      responses:
        "200":
          description: PNG image
          content:
            image/png:
              schema:
                type: string
                format: binary
        "400":
          description: Validation error
        "401":
          description: Missing or invalid token
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
    apiTokenQuery:
      type: apiKey
      in: query
      name: api_token
tags:
  - name: Trackers
  - name: Visits
  - name: Reports
  - name: Analytics
  - name: QR
