{
  "openapi": "3.0.3",
  "info": {
    "title": "QRalto Public API",
    "version": "1.0.0",
    "description": "Scoped API-key access to QR campaigns and privacy-first scan analytics."
  },
  "servers": [{ "url": "https://api.qralto.com", "description": "Production" }],
  "security": [{ "ApiKey": [] }],
  "paths": {
    "/api/v1/qr-codes": {
      "get": {
        "summary": "List QR campaigns",
        "operationId": "listQrCodes",
        "parameters": [
          { "$ref": "#/components/parameters/Page" },
          { "$ref": "#/components/parameters/PageSize" },
          { "name": "search", "in": "query", "schema": { "type": "string" } },
          { "name": "mode", "in": "query", "schema": { "$ref": "#/components/schemas/QrCodeMode" } },
          { "name": "isActive", "in": "query", "schema": { "type": "boolean" } }
        ],
        "responses": {
          "200": { "description": "A tenant-isolated page of campaigns.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PagedQrCodes" } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      },
      "post": {
        "summary": "Create a QR campaign",
        "operationId": "createQrCode",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateQrCodeRequest" } } } },
        "responses": {
          "201": { "description": "Campaign created.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/QrCodeDetails" } } } },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "402": { "$ref": "#/components/responses/PaymentRequired" }
        }
      }
    },
    "/api/v1/qr-codes/{id}": {
      "parameters": [{ "$ref": "#/components/parameters/QrCodeId" }],
      "get": {
        "summary": "Get a QR campaign",
        "operationId": "getQrCode",
        "responses": {
          "200": { "description": "Campaign details.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/QrCodeDetails" } } } },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      },
      "put": {
        "summary": "Update a QR campaign",
        "operationId": "updateQrCode",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateQrCodeRequest" } } } },
        "responses": {
          "200": { "description": "Campaign updated.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/QrCodeDetails" } } } },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      },
      "delete": {
        "summary": "Delete a QR campaign",
        "operationId": "deleteQrCode",
        "responses": {
          "204": { "description": "Campaign soft-deleted and no longer available." },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/api/v1/qr-codes/{id}/status": {
      "put": {
        "summary": "Activate or pause a campaign",
        "operationId": "updateQrCodeStatus",
        "parameters": [{ "$ref": "#/components/parameters/QrCodeId" }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["isActive"], "properties": { "isActive": { "type": "boolean" } } } } } },
        "responses": {
          "200": { "description": "Status updated.", "content": { "application/json": { "schema": { "type": "object", "required": ["id", "isActive"], "properties": { "id": { "type": "string", "format": "uuid" }, "isActive": { "type": "boolean" } } } } } },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/api/v1/qr-codes/{id}/download": {
      "get": {
        "summary": "Download rendered QR artwork",
        "operationId": "downloadQrCode",
        "parameters": [
          { "$ref": "#/components/parameters/QrCodeId" },
          { "name": "format", "in": "query", "schema": { "type": "string", "enum": ["png", "svg"], "default": "png" } }
        ],
        "responses": {
          "200": { "description": "PNG or SVG artwork.", "content": { "image/png": { "schema": { "type": "string", "format": "binary" } }, "image/svg+xml": { "schema": { "type": "string", "format": "binary" } } } },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/api/v1/qr-assets": {
      "post": {
        "summary": "Upload a file for a paperless QR page",
        "description": "Uploads a genuine PNG, JPG, or passive PDF. The returned ID remains private until it is attached to a tenant-owned QR campaign.",
        "operationId": "uploadQrAsset",
        "requestBody": { "required": true, "content": { "multipart/form-data": { "schema": { "type": "object", "required": ["file"], "properties": { "file": { "type": "string", "format": "binary" } } } } } },
        "responses": {
          "201": { "description": "Inspected upload accepted.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/QrAssetUpload" } } } },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "402": { "$ref": "#/components/responses/PaymentRequired" }
        }
      }
    },
    "/api/v1/qr-assets/{id}": {
      "delete": {
        "summary": "Delete an unattached upload",
        "operationId": "deleteQrAsset",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }],
        "responses": {
          "204": { "description": "Unattached tenant-owned upload deleted." },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/api/v1/analytics/overview": {
      "get": {
        "summary": "Read scan analytics",
        "operationId": "getAnalyticsOverview",
        "parameters": [
          { "name": "qrCodeId", "in": "query", "schema": { "type": "string", "format": "uuid" } },
          { "name": "fromUtc", "in": "query", "schema": { "type": "string", "format": "date-time" } },
          { "name": "toUtc", "in": "query", "schema": { "type": "string", "format": "date-time" } }
        ],
        "responses": {
          "200": { "description": "Aggregated workspace or campaign analytics.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AnalyticsOverview" } } } },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKey": { "type": "apiKey", "in": "header", "name": "X-Api-Key", "description": "A scoped key beginning with qra_." }
    },
    "parameters": {
      "QrCodeId": { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } },
      "Page": { "name": "page", "in": "query", "schema": { "type": "integer", "minimum": 1, "default": 1 } },
      "PageSize": { "name": "pageSize", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 20 } }
    },
    "responses": {
      "BadRequest": { "description": "The request is invalid.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiError" } } } },
      "Unauthorized": { "description": "The API key is missing, invalid, expired, or revoked.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiError" } } } },
      "Forbidden": { "description": "The key lacks the required scope or the account is unavailable.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiError" } } } },
      "PaymentRequired": { "description": "The workspace plan does not allow this capability.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiError" } } } },
      "NotFound": { "description": "The resource was not found in this workspace.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiError" } } } },
      "RateLimited": { "description": "The request rate limit was exceeded.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiError" } } } }
    },
    "schemas": {
      "ApiError": { "type": "object", "required": ["code", "message"], "properties": { "code": { "type": "string" }, "message": { "type": "string" }, "errors": { "type": "object", "nullable": true, "additionalProperties": { "type": "array", "items": { "type": "string" } } } } },
      "QrCodeMode": { "type": "string", "enum": ["Static", "Dynamic"] },
      "QrPayloadType": { "type": "string", "enum": ["Url", "Text", "Email", "Phone", "Sms", "WhatsApp", "Wifi", "VCard", "Event", "Menu", "Document", "Memory"] },
      "QrStyle": {
        "type": "object",
        "properties": {
          "templateCode": { "type": "string", "default": "Classic" },
          "experienceTemplateCode": { "type": "string", "default": "None" },
          "experienceFontFamily": { "type": "string", "enum": ["Modern", "Editorial", "Elegant", "Rounded", "Classic"], "default": "Modern" },
          "experiencePrimaryColor": { "type": "string", "pattern": "^#[0-9A-Fa-f]{6}$", "default": "#102A2A" },
          "experienceAccentColor": { "type": "string", "pattern": "^#[0-9A-Fa-f]{6}$", "default": "#357466" },
          "experienceSurfaceColor": { "type": "string", "pattern": "^#[0-9A-Fa-f]{6}$", "default": "#FFFDF8" },
          "foregroundColor": { "type": "string", "pattern": "^#[0-9A-Fa-f]{6}$", "default": "#102A2A" },
          "secondaryColor": { "type": "string", "pattern": "^#[0-9A-Fa-f]{6}$", "default": "#357466" },
          "backgroundColor": { "type": "string", "pattern": "^#[0-9A-Fa-f]{6}$", "default": "#FFFFFF" },
          "frameColor": { "type": "string", "pattern": "^#[0-9A-Fa-f]{6}$", "default": "#102A2A" },
          "useGradient": { "type": "boolean", "default": false },
          "gradientDirection": { "type": "string", "enum": ["Horizontal", "Vertical", "Diagonal"], "default": "Diagonal" },
          "moduleShape": { "type": "string", "enum": ["Square", "Rounded", "Dots"], "default": "Square" },
          "eyeFrameShape": { "type": "string", "enum": ["Square", "Rounded", "Circle"], "default": "Square" },
          "eyeBallShape": { "type": "string", "enum": ["Square", "Rounded", "Circle"], "default": "Square" },
          "frameStyle": { "type": "string", "enum": ["None", "Square", "Rounded"], "default": "None" },
          "centerBadge": { "type": "string", "enum": ["None", "Monogram", "Link", "Wifi", "Contact", "Event", "Logo"], "default": "None" },
          "centerText": { "type": "string", "maxLength": 3 },
          "logoDataUrl": { "type": "string", "nullable": true, "description": "Validated PNG data URL; maximum request size applies." },
          "errorCorrection": { "type": "string", "enum": ["Quartile", "High"], "default": "Quartile" },
          "drawQuietZones": { "type": "boolean", "default": true },
          "pixelsPerModule": { "type": "integer", "minimum": 6, "maximum": 16, "default": 16 }
        }
      },
      "CreateQrCodeRequest": { "type": "object", "required": ["name", "mode", "payloadType", "content"], "properties": { "name": { "type": "string", "maxLength": 120 }, "mode": { "$ref": "#/components/schemas/QrCodeMode" }, "payloadType": { "$ref": "#/components/schemas/QrPayloadType" }, "content": { "type": "string", "maxLength": 8000 }, "style": { "$ref": "#/components/schemas/QrStyle" } } },
      "UpdateQrCodeRequest": { "type": "object", "required": ["name", "content"], "properties": { "name": { "type": "string", "maxLength": 120 }, "content": { "type": "string", "maxLength": 8000 }, "style": { "$ref": "#/components/schemas/QrStyle" } } },
      "QrCodeSummary": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "name": { "type": "string" }, "code": { "type": "string" }, "mode": { "$ref": "#/components/schemas/QrCodeMode" }, "payloadType": { "$ref": "#/components/schemas/QrPayloadType" }, "content": { "type": "string" }, "isActive": { "type": "boolean" }, "totalScans": { "type": "integer", "format": "int64" }, "createdUtc": { "type": "string", "format": "date-time" }, "lastScannedUtc": { "type": "string", "format": "date-time", "nullable": true } } },
      "QrCodeDetails": { "allOf": [{ "$ref": "#/components/schemas/QrCodeSummary" }, { "type": "object", "properties": { "style": { "$ref": "#/components/schemas/QrStyle" }, "svg": { "type": "string" } } }] },
      "QrAssetUpload": { "type": "object", "required": ["id", "fileName", "contentType", "length"], "properties": { "id": { "type": "string", "format": "uuid" }, "fileName": { "type": "string" }, "contentType": { "type": "string", "enum": ["image/png", "image/jpeg", "application/pdf"] }, "length": { "type": "integer", "format": "int64" } } },
      "PagedQrCodes": { "type": "object", "properties": { "items": { "type": "array", "items": { "$ref": "#/components/schemas/QrCodeSummary" } }, "page": { "type": "integer" }, "pageSize": { "type": "integer" }, "totalCount": { "type": "integer" } } },
      "TimeSeriesPoint": { "type": "object", "properties": { "date": { "type": "string", "format": "date" }, "scans": { "type": "integer", "format": "int64" }, "uniqueScans": { "type": "integer", "format": "int64" } } },
      "MetricBreakdown": { "type": "object", "properties": { "label": { "type": "string" }, "scans": { "type": "integer", "format": "int64" }, "uniqueScans": { "type": "integer", "format": "int64" } } },
      "LocationBreakdown": { "type": "object", "properties": { "countryCode": { "type": "string" }, "country": { "type": "string" }, "city": { "type": "string" }, "scans": { "type": "integer", "format": "int64" }, "uniqueScans": { "type": "integer", "format": "int64" } } },
      "AnalyticsOverview": { "type": "object", "properties": { "totalScans": { "type": "integer", "format": "int64" }, "uniqueScans": { "type": "integer", "format": "int64" }, "scansInPeriod": { "type": "integer", "format": "int64" }, "changePercent": { "type": "number", "format": "decimal" }, "timeline": { "type": "array", "items": { "$ref": "#/components/schemas/TimeSeriesPoint" } }, "countries": { "type": "array", "items": { "$ref": "#/components/schemas/MetricBreakdown" } }, "cities": { "type": "array", "items": { "$ref": "#/components/schemas/LocationBreakdown" } }, "devices": { "type": "array", "items": { "$ref": "#/components/schemas/MetricBreakdown" } }, "operatingSystems": { "type": "array", "items": { "$ref": "#/components/schemas/MetricBreakdown" } }, "browsers": { "type": "array", "items": { "$ref": "#/components/schemas/MetricBreakdown" } }, "sources": { "type": "array", "items": { "$ref": "#/components/schemas/MetricBreakdown" } } } }
    }
  }
}
