{
  "openapi": "3.1.0",
  "info": {
    "title": "Humanizer Studio API",
    "version": "2.3.0",
    "description": "A shared-GPU asynchronous rewrite API with private anonymous sessions. Create a session first and pass X-Humanizer-Session when creating, reading or cancelling drafts. No account or service key is required. The configured max_concurrent_jobs share one loaded model. All slots busy returns 409. Job IDs and text are visible only to their owning session. Up to five recent jobs per session remain in RAM for an hour, within a bounded shared store. Limits: 5,000 words, 40,000 UTF-16 code units, and 200,000 JSON request bytes."
  },
  "servers": [
    {
      "url": "/",
      "description": "Same host as this specification"
    },
    {
      "url": "https://human.saeidnia.com",
      "description": "HTTPS service"
    },
    {
      "url": "http://127.0.0.1:8393",
      "description": "Server PC only"
    }
  ],
  "security": [],
  "paths": {
    "/api/v1/status": {
      "get": {
        "summary": "Inspect engine state and actual GPU offload",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "400": {
            "description": "Request rejected",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Request rejected",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Request rejected",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Request rejected",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request rejected",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "415": {
            "description": "Request rejected",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "description": "Public engine information. With a valid session header, active_job and latest_job belong only to that session. Without one, both IDs are null. engine_busy reveals no job ID or text.",
        "parameters": [
          {
            "in": "header",
            "name": "X-Humanizer-Session",
            "required": false,
            "schema": {
              "type": "string",
              "pattern": "^[a-f0-9]{64}$"
            }
          }
        ]
      }
    },
    "/api/v1/jobs": {
      "post": {
        "summary": "Start one asynchronous rewrite",
        "responses": {
          "202": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "id"
                  ],
                  "properties": {
                    "id": {
                      "type": "string",
                      "pattern": "^[a-f0-9]{32}$"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Request rejected",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Request rejected",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Request rejected",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Request rejected",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request rejected",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "415": {
            "description": "Request rejected",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Session missing or expired",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateJob"
              }
            }
          }
        },
        "security": [
          {
            "Session": []
          }
        ]
      }
    },
    "/api/v1/jobs/{id}": {
      "get": {
        "summary": "Poll a job, including partial output",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            }
          },
          "400": {
            "description": "Request rejected",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Request rejected",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Request rejected",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Request rejected",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request rejected",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "415": {
            "description": "Request rejected",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Session missing or expired",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "Session": []
          }
        ]
      },
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^[a-f0-9]{32}$"
          }
        }
      ]
    },
    "/api/v1/jobs/{id}/cancel": {
      "post": {
        "summary": "Cancel only the owning session’s job; retains partial output",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "enum": [
                        "stopping",
                        "complete",
                        "cancelled",
                        "error"
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Request rejected",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Request rejected",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Request rejected",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Request rejected",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request rejected",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "415": {
            "description": "Request rejected",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Session missing or expired",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        },
        "security": [
          {
            "Session": []
          }
        ]
      },
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^[a-f0-9]{32}$"
          }
        }
      ]
    },
    "/api/v1/unload": {
      "post": {
        "summary": "Unload the idle model",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "const": "unloaded"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Request rejected",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Request rejected",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Request rejected",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Request rejected",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request rejected",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "415": {
            "description": "Request rejected",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Session missing or expired",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        },
        "security": [
          {
            "Session": []
          }
        ]
      }
    },
    "/healthz": {
      "get": {
        "summary": "Public liveness check without draft information",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "const": "ok"
                    },
                    "version": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Request rejected",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Request rejected",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Request rejected",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Request rejected",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request rejected",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "415": {
            "description": "Request rejected",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": []
      }
    },
    "/api/v1/session": {
      "post": {
        "summary": "Start a private anonymous session",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "maxProperties": 0
              },
              "example": {}
            }
          }
        },
        "responses": {
          "201": {
            "description": "Private session created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Session"
                }
              }
            }
          },
          "400": {
            "description": "Request failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Request failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "415": {
            "description": "Request failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Request failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "FrozenRange": {
        "type": "object",
        "required": [
          "start",
          "end"
        ],
        "properties": {
          "start": {
            "type": "integer",
            "minimum": 0,
            "description": "Inclusive UTF-16 code-unit offset"
          },
          "end": {
            "type": "integer",
            "minimum": 1,
            "description": "Exclusive UTF-16 code-unit offset"
          },
          "text": {
            "type": "string",
            "readOnly": true
          }
        },
        "description": "Offsets refer to the original untrimmed text. Overlaps and adjacent ranges merge. Surrogate pairs cannot be split."
      },
      "CreateJob": {
        "type": "object",
        "required": [
          "text"
        ],
        "properties": {
          "text": {
            "type": "string",
            "minLength": 1,
            "description": "Original, untrimmed text; maximum 40,000 UTF-16 code units and 5,000 whitespace-delimited words."
          },
          "frozen_ranges": {
            "type": "array",
            "maxItems": 128,
            "default": [],
            "items": {
              "$ref": "#/components/schemas/FrozenRange"
            }
          }
        },
        "example": {
          "text": "The garden has 12 beds. Volunteers water it each Saturday.",
          "frozen_ranges": [
            {
              "start": 0,
              "end": 23
            }
          ]
        }
      },
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string"
          }
        }
      },
      "DetailCheck": {
        "type": "object",
        "required": [
          "missing_numbers",
          "extra_numbers",
          "citations_preserved",
          "truncated",
          "frozen_total",
          "frozen_kept"
        ],
        "properties": {
          "missing_numbers": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "extra_numbers": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "citations_preserved": {
            "type": "boolean"
          },
          "truncated": {
            "type": "boolean"
          },
          "frozen_total": {
            "type": "integer"
          },
          "frozen_kept": {
            "type": "integer"
          },
          "protected_passages_kept": {
            "type": "integer",
            "minimum": 0
          }
        }
      },
      "Job": {
        "type": "object",
        "required": [
          "id",
          "stage",
          "input",
          "output",
          "error",
          "frozen_ranges",
          "frozen_output_ranges",
          "completed_chunks",
          "total_chunks",
          "tokens_generated",
          "started_at",
          "elapsed_seconds",
          "check"
        ],
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^[a-f0-9]{32}$"
          },
          "stage": {
            "type": "string",
            "enum": [
              "queued",
              "loading",
              "tokenizing",
              "generating",
              "complete",
              "cancelled",
              "error"
            ]
          },
          "input": {
            "type": "string"
          },
          "output": {
            "type": "string"
          },
          "error": {
            "type": [
              "string",
              "null"
            ]
          },
          "frozen_ranges": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FrozenRange"
            }
          },
          "frozen_output_ranges": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FrozenRange"
            }
          },
          "completed_chunks": {
            "type": "integer",
            "minimum": 0
          },
          "total_chunks": {
            "type": "integer",
            "minimum": 0
          },
          "tokens_generated": {
            "type": "integer",
            "minimum": 0
          },
          "started_at": {
            "type": "number",
            "description": "Unix timestamp in seconds"
          },
          "finished_at": {
            "type": "number",
            "description": "Present after termination"
          },
          "elapsed_seconds": {
            "type": "number",
            "description": "Final elapsed duration; zero while active. For live elapsed time subtract started_at from the current timestamp."
          },
          "check": {
            "anyOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/DetailCheck"
              }
            ]
          },
          "protected_passages_kept": {
            "type": "integer",
            "minimum": 0,
            "description": "Passages retained verbatim when a guarded rewrite changed frozen wording, expanded excessively, or could not fit."
          }
        }
      },
      "Status": {
        "type": "object",
        "required": [
          "status",
          "version",
          "model_state",
          "model",
          "active_job",
          "latest_job",
          "compute",
          "engine_busy",
          "max_concurrent_jobs",
          "available_slots"
        ],
        "properties": {
          "status": {
            "const": "ok"
          },
          "version": {
            "type": "string"
          },
          "model_state": {
            "enum": [
              "unloaded",
              "loading",
              "ready",
              "error"
            ]
          },
          "model": {
            "type": "string"
          },
          "active_job": {
            "type": [
              "string",
              "null"
            ],
            "description": "This session’s job ID, or null; never another session’s ID."
          },
          "latest_job": {
            "type": [
              "string",
              "null"
            ],
            "description": "This session’s job ID, or null; never another session’s ID."
          },
          "compute": {
            "type": "object",
            "properties": {
              "backend": {
                "enum": [
                  "CUDA",
                  "CUDA configured",
                  "CPU"
                ]
              },
              "gpu_name": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "gpu_layers": {
                "type": "integer"
              },
              "total_layers": {
                "type": "integer"
              },
              "requested_gpu_layers": {
                "type": "integer"
              },
              "containerized": {
                "type": "boolean"
              }
            }
          },
          "engine_busy": {
            "type": "boolean",
            "description": "The shared GPU is occupied; no other session’s job is identified."
          },
          "max_concurrent_jobs": {
            "type": "integer",
            "minimum": 1,
            "maximum": 8,
            "description": "Configured simultaneous rewrite limit."
          },
          "available_slots": {
            "type": "integer",
            "minimum": 0,
            "maximum": 8,
            "description": "Free shared rewrite slots, without exposing another session’s job IDs."
          },
          "hosting": {
            "type": "string",
            "description": "Engine deployment label."
          }
        }
      },
      "Session": {
        "type": "object",
        "required": [
          "session_id",
          "expires_in"
        ],
        "properties": {
          "session_id": {
            "type": "string",
            "pattern": "^[a-f0-9]{64}$",
            "description": "Keep private; needed to access this session’s drafts."
          },
          "expires_in": {
            "type": "integer",
            "const": 3600,
            "description": "Idle timeout in seconds; requests refresh it."
          }
        }
      }
    },
    "securitySchemes": {
      "Session": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Humanizer-Session",
        "description": "Private anonymous session returned by POST /api/v1/session; created automatically by the studio, not a manually configured service key."
      }
    }
  }
}
