{
  "openapi": "3.0.4",
  "info": {
    "title": "SYSYS.Licensing.Api | v1",
    "version": "1.0.0"
  },
  "paths": {
    "/api/health": {
      "get": {
        "tags": [
          "System"
        ],
        "summary": "Health check endpoint",
        "description": "Returns the service health status",
        "operationId": "HealthCheck",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResponseModel"
                }
              }
            }
          }
        }
      }
    },
    "/api/validate": {
      "post": {
        "tags": [
          "Validation"
        ],
        "summary": "Validate a license and issue a validation token",
        "description": "Validates the license signature, checks temporal validity and revocation status, then issues a short-lived validation token",
        "operationId": "ValidateLicense",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RequestModel"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResponseModel2"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/check-status": {
      "post": {
        "tags": [
          "Validation"
        ],
        "summary": "Check license revocation status",
        "description": "Quick status check without full validation - checks if a license has been revoked",
        "operationId": "CheckLicenseStatus",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RequestModel2"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResponseModel3"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/verify-token": {
      "post": {
        "tags": [
          "Validation"
        ],
        "summary": "Verify a previously issued validation token",
        "description": "Verifies the signature and expiry of a ValidationToken without performing a full license validation. Use this to check a cached token during grace periods or when offline verification is not possible client-side. No database calls are made — only cryptographic verification.",
        "operationId": "VerifyToken",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RequestModel3"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResponseModel4"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/heartbeat": {
      "post": {
        "tags": [
          "Heartbeat"
        ],
        "summary": "Record a heartbeat check-in",
        "description": "Clients call this endpoint at a configured interval to indicate they are still active. Missed check-ins beyond the timeout window transition the heartbeat to a dead state, causing subsequent validations to fail.",
        "operationId": "HeartbeatCheckIn",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RequestModel4"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResponseModel5"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/heartbeat/status": {
      "post": {
        "tags": [
          "Heartbeat"
        ],
        "summary": "Check heartbeat status for a license",
        "description": "Returns heartbeat status for a specific license and device, or all devices if no fingerprint is provided. Heartbeats that have exceeded the timeout window are reported as dead.",
        "operationId": "HeartbeatStatus",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RequestModel5"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResponseModel6"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/heartbeat/{licenseId}/{deviceFingerprint}": {
      "delete": {
        "tags": [
          "Heartbeat"
        ],
        "summary": "Reset a heartbeat",
        "description": "Removes the heartbeat record for a specific license and device. Used when a client deactivates or gracefully shuts down. Requires a signed license in the request body proving ownership.",
        "operationId": "HeartbeatReset",
        "parameters": [
          {
            "name": "licenseId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "deviceFingerprint",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RequestModel6"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResponseModel7"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/activations": {
      "post": {
        "tags": [
          "Activation"
        ],
        "summary": "Activate a device for a license",
        "description": "Registers a device activation against a license. If a policy with maxDevices is set, the activation is rejected when the limit is reached.",
        "operationId": "ActivateDevice",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RequestModel4"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResponseModel8"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/activations/{licenseId}/{deviceFingerprint}": {
      "delete": {
        "tags": [
          "Activation"
        ],
        "summary": "Deactivate a device",
        "description": "Removes a device activation, freeing a slot for another device. Requires a signed license in the request body proving ownership.",
        "operationId": "DeactivateDevice",
        "parameters": [
          {
            "name": "licenseId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "deviceFingerprint",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RequestModel6"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResponseModel7"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "ErrorResponse": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string"
          },
          "detail": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "HeartbeatDetail": {
        "type": "object",
        "properties": {
          "deviceFingerprint": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "lastCheckedInAt": {
            "type": "string",
            "format": "date-time"
          },
          "startedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Kid": { },
      "RequestModel": {
        "type": "object",
        "properties": {
          "signedLicense": {
            "$ref": "#/components/schemas/SignedLicense"
          },
          "deviceFingerprint": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "RequestModel2": {
        "type": "object",
        "properties": {
          "licenseId": {
            "type": "string"
          },
          "serial": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "RequestModel3": {
        "type": "object",
        "properties": {
          "token": {
            "$ref": "#/components/schemas/ValidationToken"
          },
          "deviceFingerprint": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "RequestModel4": {
        "required": [
          "signedLicense"
        ],
        "type": "object",
        "properties": {
          "licenseId": {
            "type": "string"
          },
          "serial": {
            "type": "string"
          },
          "deviceFingerprint": {
            "type": "string"
          },
          "signedLicense": {
            "$ref": "#/components/schemas/SignedLicense2"
          }
        }
      },
      "RequestModel5": {
        "required": [
          "signedLicense"
        ],
        "type": "object",
        "properties": {
          "licenseId": {
            "type": "string"
          },
          "deviceFingerprint": {
            "type": "string",
            "nullable": true
          },
          "signedLicense": {
            "$ref": "#/components/schemas/SignedLicense2"
          }
        }
      },
      "RequestModel6": {
        "required": [
          "signedLicense"
        ],
        "type": "object",
        "properties": {
          "signedLicense": {
            "$ref": "#/components/schemas/SignedLicense2"
          }
        }
      },
      "ResponseModel": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          },
          "service": {
            "type": "string"
          },
          "version": {
            "type": "string"
          }
        }
      },
      "ResponseModel2": {
        "type": "object",
        "properties": {
          "isValid": {
            "type": "boolean"
          },
          "code": {
            "type": "integer",
            "format": "int32"
          },
          "constant": {
            "type": "string"
          },
          "validationToken": {
            "$ref": "#/components/schemas/ValidationToken"
          },
          "status": {
            "type": "string"
          },
          "failureReason": {
            "type": "string",
            "nullable": true
          },
          "revocation": {
            "$ref": "#/components/schemas/SignedRevocation"
          }
        }
      },
      "ResponseModel3": {
        "type": "object",
        "properties": {
          "isRevoked": {
            "type": "boolean"
          },
          "revokedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "ResponseModel4": {
        "type": "object",
        "properties": {
          "isValid": {
            "type": "boolean"
          },
          "code": {
            "type": "integer",
            "format": "int32"
          },
          "constant": {
            "type": "string"
          },
          "licenseId": {
            "type": "string"
          },
          "serial": {
            "type": "string"
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "remainingSeconds": {
            "type": "integer",
            "format": "int64",
            "nullable": true
          },
          "failureReason": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "ResponseModel5": {
        "type": "object",
        "properties": {
          "licenseId": {
            "type": "string"
          },
          "deviceFingerprint": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "lastCheckedInAt": {
            "type": "string",
            "format": "date-time"
          },
          "nextCheckInBefore": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ResponseModel6": {
        "type": "object",
        "properties": {
          "licenseId": {
            "type": "string"
          },
          "heartbeats": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HeartbeatDetail"
            }
          }
        }
      },
      "ResponseModel7": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "licenseId": {
            "type": "string"
          },
          "deviceFingerprint": {
            "type": "string"
          }
        }
      },
      "ResponseModel8": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "code": {
            "type": "integer",
            "format": "int32"
          },
          "constant": {
            "type": "string"
          },
          "licenseId": {
            "type": "string"
          },
          "deviceFingerprint": {
            "type": "string"
          },
          "activationCount": {
            "type": "integer",
            "format": "int32"
          },
          "maxDevices": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          }
        }
      },
      "RevocationPayload": {
        "required": [
          "licenseId",
          "serial",
          "reason",
          "revokedAt",
          "revokedBy"
        ],
        "type": "object",
        "properties": {
          "licenseId": {
            "type": "string"
          },
          "serial": {
            "type": "string"
          },
          "reason": {
            "type": "string"
          },
          "revokedAt": {
            "type": "string",
            "format": "date-time"
          },
          "revokedBy": {
            "type": "string"
          }
        }
      },
      "Serial": { },
      "Signature": { },
      "SignedLicense": {
        "nullable": true
      },
      "SignedLicense2": { },
      "SignedRevocation": {
        "required": [
          "payload",
          "keyId",
          "signature"
        ],
        "type": "object",
        "properties": {
          "payload": {
            "$ref": "#/components/schemas/RevocationPayload"
          },
          "keyId": {
            "$ref": "#/components/schemas/Kid"
          },
          "signature": {
            "$ref": "#/components/schemas/Signature"
          }
        },
        "nullable": true
      },
      "ValidationToken": {
        "type": "object",
        "properties": {
          "licenseId": {
            "$ref": "#/components/schemas/Serial"
          },
          "serial": {
            "$ref": "#/components/schemas/Serial"
          },
          "issuedAt": {
            "type": "string",
            "format": "date-time"
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time"
          },
          "deviceFingerprint": {
            "type": "string",
            "nullable": true
          },
          "keyId": {
            "type": "string"
          },
          "signature": {
            "type": "string"
          }
        },
        "nullable": true
      }
    }
  },
  "tags": [
    {
      "name": "System"
    },
    {
      "name": "Validation"
    },
    {
      "name": "Heartbeat"
    },
    {
      "name": "Activation"
    }
  ]
}