{
  "openapi": "3.1.0",
  "info": {
    "title": "Citely Citation Integrity API",
    "version": "1.0.0",
    "description": "Verify already-separated scholarly citations across leading global and Chinese scholarly sources. A not_found result means no reliable match was found; it is not proof that a citation is fabricated."
  },
  "servers": [{ "url": "https://citely.ai" }],
  "security": [{ "bearerAuth": [] }],
  "paths": {
    "/api/v1/citation-checks": {
      "post": {
        "operationId": "startCitationIntegrityCheck",
        "summary": "Start a citation integrity check",
        "description": "Starts an asynchronous check for 1–80 already-separated citations. Citely charges 1 Credit per 4 citations. Technical failures are refunded according to the service billing rules.",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "description": "A stable, unique key for safe retries. Reusing a key with different content returns 409.",
            "schema": { "type": "string", "minLength": 1, "maxLength": 200 }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/StartCitationCheckRequest" },
              "example": {
                "items": [
                  {
                    "id": "ref-1",
                    "content": "Smith, J. (2024). Example article. Journal of Examples, 1(2), 3–9."
                  }
                ],
                "locale": "en-US"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Existing idempotent job already completed or failed",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/StartCitationCheckResponse" } } }
          },
          "202": {
            "description": "Job accepted or still processing",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/StartCitationCheckResponse" } } }
          },
          "400": { "$ref": "#/components/responses/InvalidRequest" },
          "401": { "$ref": "#/components/responses/AuthenticationRequired" },
          "402": {
            "description": "Insufficient Citely Credits",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiError" } } }
          },
          "409": {
            "description": "The idempotency key was already used with different content",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiError" } } }
          },
          "429": {
            "description": "More than 3 new jobs were started by this user within one minute",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiError" } } }
          },
          "503": { "$ref": "#/components/responses/ServiceUnavailable" }
        }
      }
    },
    "/api/v1/citation-checks/{jobId}": {
      "get": {
        "operationId": "getCitationIntegrityCheck",
        "summary": "Get citation integrity progress and results",
        "parameters": [
          {
            "name": "jobId",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "minLength": 1, "maxLength": 200 }
          }
        ],
        "responses": {
          "200": {
            "description": "Current job state and available results",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CitationJob" } } }
          },
          "400": { "$ref": "#/components/responses/InvalidRequest" },
          "401": { "$ref": "#/components/responses/AuthenticationRequired" },
          "404": {
            "description": "Job not found or not owned by the authenticated account",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiError" } } }
          },
          "503": { "$ref": "#/components/responses/ServiceUnavailable" }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "Citely API Key",
        "description": "Use a Citely API key beginning with sk-."
      }
    },
    "responses": {
      "InvalidRequest": {
        "description": "Invalid request",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiError" } } }
      },
      "AuthenticationRequired": {
        "description": "Missing, invalid, or revoked API key",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiError" } } }
      },
      "ServiceUnavailable": {
        "description": "Temporary service failure",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiError" } } }
      }
    },
    "schemas": {
      "VerificationStatus": {
        "type": "string",
        "enum": ["verified", "mismatch", "not_found"],
        "description": "not_found means no reliable match was found; it does not prove fabrication."
      },
      "JobStatus": {
        "type": "string",
        "enum": ["processing", "completed", "failed"]
      },
      "CitationInput": {
        "type": "object",
        "additionalProperties": false,
        "required": ["id", "content"],
        "properties": {
          "id": { "type": "string", "minLength": 1, "maxLength": 200 },
          "content": { "type": "string", "minLength": 1, "maxLength": 5000 }
        }
      },
      "StartCitationCheckRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": ["items"],
        "properties": {
          "items": {
            "type": "array",
            "minItems": 1,
            "maxItems": 80,
            "items": { "$ref": "#/components/schemas/CitationInput" }
          },
          "locale": { "type": "string", "maxLength": 20 }
        }
      },
      "StartCitationCheckResponse": {
        "type": "object",
        "required": ["jobId", "status", "totalItems", "estimatedCredits", "creditsCharged"],
        "properties": {
          "jobId": { "type": "string" },
          "status": { "$ref": "#/components/schemas/JobStatus" },
          "totalItems": { "type": "integer", "minimum": 1 },
          "estimatedCredits": { "type": "number" },
          "creditsCharged": { "type": "number" },
          "pollAfterSeconds": { "type": "integer", "minimum": 1 }
        }
      },
      "PublicReference": {
        "type": "object",
        "description": "Public evidence and metadata comparison for one citation. Fields may be omitted when unavailable.",
        "properties": {
          "title": { "type": "string" },
          "authors": { "type": "array", "items": { "type": "string" } },
          "year": { "type": "string" },
          "doi": { "type": "string" },
          "url": { "type": "string", "format": "uri" },
          "source": { "type": "string" },
          "matchedTitle": { "type": "string" },
          "matchedAuthors": { "type": "array", "items": { "type": "string" } },
          "matchedYear": { "type": "string" },
          "similarity": { "type": "number" }
        }
      },
      "CitationResultItem": {
        "type": "object",
        "required": ["id", "content"],
        "properties": {
          "id": { "type": "string" },
          "content": { "type": "string" },
          "pending": { "type": "boolean" },
          "result": {
            "type": "object",
            "required": ["status", "reference"],
            "properties": {
              "status": { "$ref": "#/components/schemas/VerificationStatus" },
              "reference": { "$ref": "#/components/schemas/PublicReference" }
            }
          },
          "error": {
            "type": "object",
            "required": ["code", "retryable"],
            "properties": {
              "code": {
                "type": "string",
                "enum": ["required_provider_failed", "verification_failed", "execution_deadline_budget_exhausted", "execution_abandoned"]
              },
              "retryable": { "type": "boolean" }
            }
          }
        }
      },
      "CitationJob": {
        "type": "object",
        "required": ["jobId", "status", "totalItems", "completedItems", "progress", "summary", "billing", "items"],
        "properties": {
          "jobId": { "type": "string" },
          "status": { "$ref": "#/components/schemas/JobStatus" },
          "totalItems": { "type": "integer" },
          "completedItems": { "type": "integer" },
          "progress": { "type": "number" },
          "pollAfterSeconds": { "type": "integer" },
          "summary": {
            "type": "object",
            "required": ["total", "verified", "mismatch", "notFound", "failed"],
            "properties": {
              "total": { "type": "integer" },
              "verified": { "type": "integer" },
              "mismatch": { "type": "integer" },
              "notFound": { "type": "integer" },
              "failed": { "type": "integer" }
            }
          },
          "billing": {
            "type": "object",
            "required": ["creditsCharged", "creditsRefunded"],
            "properties": {
              "creditsCharged": { "type": "number" },
              "creditsRefunded": { "type": "number" }
            }
          },
          "items": { "type": "array", "items": { "$ref": "#/components/schemas/CitationResultItem" } },
          "error": {
            "type": "object",
            "properties": {
              "code": { "type": "string" },
              "message": { "type": "string" }
            }
          }
        }
      },
      "ApiError": {
        "type": "object",
        "required": ["code", "message", "requestId"],
        "properties": {
          "code": { "type": "string" },
          "message": { "type": "string" },
          "requestId": { "type": "string" },
          "available": { "type": "number" },
          "required": { "type": "number" },
          "retryAfterSeconds": { "type": "integer" }
        }
      }
    }
  }
}
