{
  "openapi": "3.0.3",
  "info": {
    "title": "Roux Hosted API",
    "version": "1",
    "x-roux-product-version": "4.0",
    "description": "The profile-aware Roux V4 hosted surface. A deployment uses either external bearer authentication, native opaque cookie sessions, or loopback-only development bearer authentication. Route availability also depends on workspace mode and runtime policy. See /roux-api-docs.html for the implementation-grounded guide.",
    "contact": { "name": "Roux" }
  },
  "servers": [{ "url": "https://your-roux-host", "description": "Your Roux hosted deployment" }],
  "security": [{ "bearerAuth": [] }, { "rouxSessionHeader": [] }, { "nativeSession": [] }],
  "tags": [
    { "name": "REST reads", "description": "Governed state and in-memory row reads." },
    { "name": "Operations", "description": "Capability-gated engine operations." },
    { "name": "Import", "description": "Authorized streamed workspace import." },
    { "name": "Native authentication", "description": "Opaque cookie-session lifecycle, present only in native mode." },
    { "name": "Development authentication", "description": "Loopback-only development bearer issuance; absent from production profiles." },
    { "name": "Health", "description": "Unauthenticated liveness and readiness." }
  ],
  "paths": {
    "/api/v1/state": {
      "get": {
        "tags": ["REST reads"],
        "summary": "Get the authorized workspace specification",
        "description": "Available when workspace-mode transport exposes getState. The workspace selector is resolved server-side and is not proof of authorization. In ordinary workspace mode, a missing, unknown, or non-member selector resolves to the caller's isolated personal workspace; constrained profiles can impose a stricter fixed target.",
        "operationId": "getState",
        "parameters": [{ "$ref": "#/components/parameters/ws" }, { "$ref": "#/components/parameters/workspaceHeader" }],
        "responses": {
          "200": { "description": "Authorized workspace specification and optimistic-concurrency version. A new personal workspace can have null state and version 0.", "content": { "application/json": { "schema": { "type": "object", "required": ["ok", "data"], "properties": { "ok": { "type": "boolean", "enum": [true] }, "data": { "type": "object", "required": ["state", "version"], "properties": { "state": { "type": "object", "nullable": true }, "version": { "type": "integer", "minimum": 0 } } } } } } } },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "description": "Authorization context, engine dispatch, or tenant scope failed.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorEnvelope" } } } },
          "503": { "$ref": "#/components/responses/Unavailable" }
        }
      }
    },
    "/api/v1/rows/{id}": {
      "get": {
        "tags": ["REST reads"],
        "summary": "Get an authorized in-memory row slice",
        "description": "Returns rows after server-side authorization and applicable row/column policy. Workspace owners retain full-row access. DuckDB-backed datasets do not materialize their complete contents here; use page for bounded rows and query for aggregation through /call.",
        "operationId": "getRows",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "description": "Dataset identifier.", "schema": { "type": "string" } },
          { "$ref": "#/components/parameters/ws" },
          { "$ref": "#/components/parameters/workspaceHeader" }
        ],
        "responses": {
          "200": { "description": "Authorized rows and version.", "content": { "application/json": { "schema": { "type": "object", "required": ["ok", "data"], "properties": { "ok": { "type": "boolean", "enum": [true] }, "data": { "type": "object", "required": ["rows", "version"], "properties": { "rows": { "type": "array", "items": { "type": "object" } }, "version": { "type": "integer", "minimum": 0 } } } } } } } },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "description": "Authorization context, engine dispatch, or tenant scope failed.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorEnvelope" } } } },
          "503": { "$ref": "#/components/responses/Unavailable" }
        }
      }
    },
    "/api/v1/upload": {
      "post": {
        "tags": ["Import"],
        "summary": "Stream an authorized file into a workspace",
        "description": "Workspace-mode write route for CSV, TSV, or Parquet. Authentication and upload authorization run before body bytes are read. The body streams with backpressure to a private server temporary file before ingestion. The constrained public-demo profile denies this route.",
        "operationId": "uploadDataset",
        "security": [{ "bearerAuth": [] }, { "rouxSessionHeader": [] }, { "nativeSession": [], "nativeCsrf": [] }],
        "parameters": [
          { "$ref": "#/components/parameters/ws" },
          { "$ref": "#/components/parameters/workspaceHeader" },
          { "name": "x-roux-filename", "in": "header", "required": false, "description": "Display filename ending in .csv, .tsv, or .parquet. Omission defaults to upload.csv.", "schema": { "type": "string", "default": "upload.csv" } }
        ],
        "requestBody": { "required": true, "content": { "application/octet-stream": { "schema": { "type": "string", "format": "binary" } }, "text/csv": { "schema": { "type": "string", "format": "binary" } } } },
        "responses": {
          "200": { "description": "Import completed.", "content": { "application/json": { "schema": { "type": "object", "required": ["ok", "value"], "properties": { "ok": { "type": "boolean", "enum": [true] }, "value": {} } } } } },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "408": { "description": "Upload body stalled.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorEnvelope" } } } },
          "413": { "description": "Configured upload byte ceiling exceeded.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorEnvelope" } } } },
          "415": { "description": "Unsupported file extension.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorEnvelope" } } } },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "description": "Temporary file or ingestion failure.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorEnvelope" } } } },
          "503": { "$ref": "#/components/responses/Unavailable" }
        }
      }
    },
    "/call": {
      "post": {
        "tags": ["Operations"],
        "summary": "Invoke a network-allowed operation",
        "description": "Sends {op,args}. The health operation is the only unauthenticated network operation; every other network operation requires the deployment-selected credential shown below. Success is HTTP 200 with {ok:true,value}. A typed engine failure preserves {ok:false,error} and uses its typed HTTP status. Desktop-only, secret, unknown, or unauthorized operations are refused.",
        "operationId": "call",
        "x-roux-public-operations": ["health"],
        "x-roux-security-model": "OpenAPI cannot make security conditional on the request body's op field. The security array intentionally models the fail-closed authenticated case; x-roux-public-operations names the sole runtime exception.",
        "security": [{ "bearerAuth": [] }, { "rouxSessionHeader": [] }, { "nativeSession": [], "nativeCsrf": [] }],
        "parameters": [{ "$ref": "#/components/parameters/ws" }, { "$ref": "#/components/parameters/workspaceHeader" }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["op"], "properties": { "op": { "type": "string" }, "args": { "type": "object" } } } } } },
        "responses": {
          "200": { "description": "Successful engine envelope.", "content": { "application/json": { "schema": { "type": "object", "required": ["ok", "value"], "properties": { "ok": { "type": "boolean", "enum": [true] }, "value": {} } } } } },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "413": { "description": "JSON body exceeds the operation-channel ceiling.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorEnvelope" } } } },
          "415": { "description": "Content-Type must be application/json.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorEnvelope" } } } },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "409": { "description": "Version, lifecycle, or storage conflict. A stale write carries error.code STATE_VERSION_CONFLICT with error.currentVersion; branch on the code rather than the status.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorEnvelope" } } } },
          "422": { "description": "The operation cannot execute on the requested path; inspect fallback markers where present.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorEnvelope" } } } },
          "500": { "description": "Typed internal operation failure.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorEnvelope" } } } },
          "503": { "$ref": "#/components/responses/Unavailable" },
          "default": { "description": "Typed operation failure.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorEnvelope" } } } }
        }
      }
    },
    "/login": {
      "post": {
        "tags": ["Development authentication"],
        "summary": "Issue an admitted loopback development bearer token",
        "description": "Present only when ROUX_DEV_LOGIN is explicitly enabled with a symmetric secret, no public key/JWKS/real IdP, and a loopback-only server. It never issues embed credentials. The route is absent in production profiles.",
        "operationId": "devLogin",
        "security": [],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "additionalProperties": false, "required": ["sub"], "properties": { "sub": { "type": "string", "minLength": 1, "pattern": "\\S" }, "org": { "type": "string", "minLength": 1 }, "memberships": { "type": "array", "items": { "type": "object", "required": ["ws"], "properties": { "ws": { "type": "string", "minLength": 1 }, "role": { "type": "string", "enum": ["owner", "editor", "viewer"] } } } }, "attributes": { "type": "object", "additionalProperties": true } } } } } },
        "responses": {
          "200": { "description": "Admitted ordinary development token.", "content": { "application/json": { "schema": { "type": "object", "required": ["ok", "token"], "properties": { "ok": { "type": "boolean", "enum": [true] }, "token": { "type": "string", "minLength": 1 } } } } } },
          "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" },
          "413": { "$ref": "#/components/responses/PayloadTooLarge" }, "415": { "$ref": "#/components/responses/UnsupportedMediaType" },
          "503": { "$ref": "#/components/responses/Unavailable" }
        }
      }
    },
    "/auth/config": {
      "get": {
        "tags": ["Native authentication"], "summary": "Get public native-auth capabilities", "operationId": "authConfig", "security": [],
        "responses": { "200": { "description": "Public configuration.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AuthConfigEnvelope" } } } }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "503": { "$ref": "#/components/responses/Unavailable" } }
      }
    },
    "/auth/session": {
      "get": {
        "tags": ["Native authentication"], "summary": "Get the current native session projection", "operationId": "authSession", "security": [{ "nativeSession": [] }],
        "parameters": [{ "$ref": "#/components/parameters/ws" }, { "$ref": "#/components/parameters/workspaceHeader" }],
        "responses": { "200": { "description": "Session projection and CSRF value.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AuthSessionEnvelope" } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "503": { "$ref": "#/components/responses/Unavailable" } }
      }
    },
    "/auth/mfa": {
      "get": {
        "tags": [
          "Native authentication"
        ],
        "summary": "Get the second-factor enrolment status for the current native session",
        "operationId": "authMfaStatus",
        "security": [
          {
            "nativeSession": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ws"
          },
          {
            "$ref": "#/components/parameters/workspaceHeader"
          }
        ],
        "responses": {
          "200": {
            "description": "Enrolment projection: state, confirmedAt, recoveryRemaining. Never a secret, URI, or recovery code.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    }
                  },
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "description": "Version, lifecycle, or storage conflict.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/auth/mfa/complete": {
      "post": {
        "tags": [
          "Native authentication"
        ],
        "summary": "Complete a second-factor step-up and receive the session it earns",
        "operationId": "authMfaComplete",
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/ws"
          },
          {
            "$ref": "#/components/parameters/workspaceHeader"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "mfaToken",
                  "code"
                ],
                "properties": {
                  "mfaToken": {
                    "type": "string",
                    "minLength": 1
                  },
                  "code": {
                    "type": "string",
                    "minLength": 1
                  }
                },
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Session projection and CSRF value; the step-up token grants nothing on its own.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    }
                  },
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "description": "Version, lifecycle, or storage conflict.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/auth/mfa/enrol": {
      "post": {
        "tags": [
          "Native authentication"
        ],
        "summary": "Begin second-factor enrolment (requires the password; secret, URI and recovery codes are returned exactly once)",
        "operationId": "authMfaEnrol",
        "security": [
          {
            "nativeSession": [],
            "nativeCsrf": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ws"
          },
          {
            "$ref": "#/components/parameters/workspaceHeader"
          }
        ],
        "requestBody": {
          "required": true,
          "description": "The account's current password. A live session alone cannot install a second factor: it would let whoever holds the session enrol their own authenticator on an account that has none yet.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "password"
                ],
                "properties": {
                  "password": {
                    "$ref": "#/components/schemas/AuthPassword"
                  }
                },
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Secret, otpauth URI and recovery codes, returned ONCE and never readable again.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    }
                  },
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "description": "Version, lifecycle, or storage conflict.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          },
          "409": {
            "description": "Version, lifecycle, or storage conflict.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/auth/mfa/enrol/confirm": {
      "post": {
        "tags": [
          "Native authentication"
        ],
        "summary": "Confirm enrolment with a TOTP code",
        "operationId": "authMfaEnrolConfirm",
        "security": [
          {
            "nativeSession": [],
            "nativeCsrf": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ws"
          },
          {
            "$ref": "#/components/parameters/workspaceHeader"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "code"
                ],
                "properties": {
                  "code": {
                    "type": "string",
                    "minLength": 1
                  }
                },
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Enrolment projection; the session is NOT upgraded — one more sign-in with the code is owed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    }
                  },
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "description": "Version, lifecycle, or storage conflict.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          },
          "409": {
            "description": "Version, lifecycle, or storage conflict.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/auth/mfa/disable": {
      "post": {
        "tags": [
          "Native authentication"
        ],
        "summary": "Remove the second factor (requires the password and a multi-factor session)",
        "operationId": "authMfaDisable",
        "security": [
          {
            "nativeSession": [],
            "nativeCsrf": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ws"
          },
          {
            "$ref": "#/components/parameters/workspaceHeader"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "password"
                ],
                "properties": {
                  "password": {
                    "type": "string",
                    "minLength": 1
                  }
                },
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Enrolment projection with state none.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    }
                  },
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "description": "Version, lifecycle, or storage conflict.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          },
          "409": {
            "description": "Version, lifecycle, or storage conflict.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/auth/mfa/recovery-codes": {
      "post": {
        "tags": [
          "Native authentication"
        ],
        "summary": "Replace every recovery code (requires the password and a multi-factor session)",
        "operationId": "authMfaRecoveryCodes",
        "security": [
          {
            "nativeSession": [],
            "nativeCsrf": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ws"
          },
          {
            "$ref": "#/components/parameters/workspaceHeader"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "password"
                ],
                "properties": {
                  "password": {
                    "type": "string",
                    "minLength": 1
                  }
                },
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "A fresh recovery-code set, returned once. Every previous code stops working.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    }
                  },
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "description": "Version, lifecycle, or storage conflict.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          },
          "409": {
            "description": "Version, lifecycle, or storage conflict.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/auth/login": {
      "post": {
        "tags": ["Native authentication"], "summary": "Start an opaque native session", "operationId": "authLogin", "security": [],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["orgId", "login", "password"], "properties": { "orgId": { "$ref": "#/components/schemas/AuthInputText" }, "login": { "$ref": "#/components/schemas/AuthInputText" }, "password": { "$ref": "#/components/schemas/AuthPassword" } } } } } },
        "responses": { "200": { "description": "Session cookie, projection, and CSRF value.", "headers": { "Set-Cookie": { "$ref": "#/components/headers/NativeSessionCookie" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AuthSessionEnvelope" } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "413": { "$ref": "#/components/responses/PayloadTooLarge" }, "415": { "$ref": "#/components/responses/UnsupportedMediaType" }, "429": { "$ref": "#/components/responses/RateLimited" }, "503": { "$ref": "#/components/responses/Unavailable" } }
      }
    },
    "/auth/logout": {
      "post": {
        "tags": ["Native authentication"], "summary": "Revoke the current native session", "operationId": "authLogout", "security": [{ "nativeSession": [], "nativeCsrf": [] }],
        "requestBody": { "required": true, "description": "Send an application/json empty object. The route requires JSON Content-Type even though it needs no body fields.", "content": { "application/json": { "schema": { "type": "object", "additionalProperties": false } } } },
        "responses": { "204": { "description": "Session revoked and cookie cleared.", "headers": { "Set-Cookie": { "$ref": "#/components/headers/NativeSessionCookie" } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "413": { "$ref": "#/components/responses/PayloadTooLarge" }, "415": { "$ref": "#/components/responses/UnsupportedMediaType" }, "503": { "$ref": "#/components/responses/Unavailable" } }
      }
    },
    "/auth/activate": {
      "post": {
        "tags": ["Native authentication"], "summary": "Activate an operator-provisioned native account", "operationId": "authActivate", "security": [],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["orgId", "login", "activation", "newPassword"], "properties": { "orgId": { "$ref": "#/components/schemas/AuthInputText" }, "login": { "$ref": "#/components/schemas/AuthInputText" }, "activation": { "$ref": "#/components/schemas/AuthInputText" }, "newPassword": { "$ref": "#/components/schemas/AuthPassword" } } } } } },
        "responses": { "200": { "description": "Account activated.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OkEnvelope" } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "413": { "$ref": "#/components/responses/PayloadTooLarge" }, "415": { "$ref": "#/components/responses/UnsupportedMediaType" }, "429": { "$ref": "#/components/responses/RateLimited" }, "503": { "$ref": "#/components/responses/Unavailable" } }
      }
    },
    "/auth/change-password": {
      "post": {
        "tags": ["Native authentication"], "summary": "Change the current native password and rotate the session", "operationId": "authChangePassword", "security": [{ "nativeSession": [], "nativeCsrf": [] }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["currentPassword", "newPassword"], "properties": { "currentPassword": { "$ref": "#/components/schemas/AuthPassword" }, "newPassword": { "$ref": "#/components/schemas/AuthPassword" } } } } } },
        "responses": { "200": { "description": "Password changed; replacement cookie and CSRF value returned.", "headers": { "Set-Cookie": { "$ref": "#/components/headers/NativeSessionCookie" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AuthSessionEnvelope" } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "413": { "$ref": "#/components/responses/PayloadTooLarge" }, "415": { "$ref": "#/components/responses/UnsupportedMediaType" }, "429": { "$ref": "#/components/responses/RateLimited" }, "503": { "$ref": "#/components/responses/Unavailable" } }
      }
    },
    "/healthz": {
      "get": { "tags": ["Health"], "summary": "Process liveness", "operationId": "healthz", "security": [], "responses": { "200": { "description": "Process is live.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Liveness" } } } } } }
    },
    "/readyz": {
      "get": { "tags": ["Health"], "summary": "Deployment readiness", "operationId": "readyz", "security": [], "responses": { "200": { "description": "Ready.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Readiness" } } } }, "503": { "description": "Unready.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Readiness" } } } } } }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT", "description": "Authorization header accepted for a verified ordinary external/development token or a valid Roux-minted derived credential. Never self-assert Roux derived embed/publication fields on an ordinary token." },
      "rouxSessionHeader": { "type": "apiKey", "in": "header", "name": "x-roux-session", "description": "Compatibility header accepted for a verified ordinary external/development token or valid Roux-minted derived credential. Do not present it together with a native session cookie." },
      "nativeSession": { "type": "apiKey", "in": "cookie", "name": "__Host-roux-session", "description": "Opaque Secure/HttpOnly server-side session cookie established by native login." },
      "nativeCsrf": { "type": "apiKey", "in": "header", "name": "x-roux-csrf", "description": "Session-bound CSRF value required with nativeSession for every authenticated POST /call and POST /api/v1/upload request, including read operations sent through /call. The public health operation is the explicit exception." }
    },
    "parameters": {
      "ws": { "name": "ws", "in": "query", "required": false, "description": "Workspace selector; never proof of authorization.", "schema": { "type": "string" } },
      "workspaceHeader": { "name": "x-roux-workspace", "in": "header", "required": false, "description": "Workspace selector; never proof of authorization. Header takes precedence over the ws query value.", "schema": { "type": "string" } }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": ["message"],
        "properties": {
          "message": { "type": "string" }, "code": { "type": "string" }, "status": { "type": "integer" },
          "reason": { "type": "string" }, "retryable": { "type": "boolean" }, "storage": { "type": "boolean" },
          "state": { "type": "string", "nullable": true }, "unit": { "type": "string", "nullable": true },
          "currentVersion": { "type": "integer" }, "conflict": { "type": "boolean" }, "fallback": {},
          "notFound": { "type": "boolean" }, "datasetTooLarge": { "type": "boolean" }, "partial": { "type": "boolean" },
          "causeCode": { "type": "string" }
        }
      },
      "ErrorEnvelope": { "type": "object", "required": ["ok", "error"], "properties": { "ok": { "type": "boolean", "enum": [false] }, "error": { "$ref": "#/components/schemas/Error" } } },
      "AuthInputText": { "type": "string", "minLength": 1, "maxLength": 1024, "x-roux-max-utf8-bytes": 1024, "x-roux-control-characters": "forbidden" },
      "AuthPassword": { "type": "string", "format": "password", "minLength": 1, "maxLength": 1024, "x-roux-max-utf8-bytes": 1024, "x-roux-control-characters": "forbidden" },
      "OkEnvelope": { "type": "object", "required": ["ok"], "properties": { "ok": { "type": "boolean", "enum": [true] } } },
      "AuthConfigEnvelope": { "type": "object", "required": ["ok", "mode", "capabilities", "assuranceLevel", "methods"], "properties": { "ok": { "type": "boolean", "enum": [true] }, "mode": { "type": "string" }, "capabilities": { "type": "object", "required": ["login", "activation", "changePassword", "serverSession", "credentialAdmin", "organizationRequired"], "properties": { "login": { "type": "boolean" }, "activation": { "type": "boolean" }, "changePassword": { "type": "boolean" }, "serverSession": { "type": "boolean" }, "credentialAdmin": { "type": "boolean" }, "organizationRequired": { "type": "boolean" } } }, "assuranceLevel": { "type": "string" }, "methods": { "type": "array", "items": { "type": "string" } } } },
      "AuthSessionEnvelope": { "type": "object", "required": ["ok", "session", "csrfToken"], "properties": { "ok": { "type": "boolean", "enum": [true] }, "session": { "type": "object", "additionalProperties": true }, "csrfToken": { "type": "string", "minLength": 43, "maxLength": 43 } } },
      "Liveness": { "type": "object", "required": ["ok", "status"], "properties": { "ok": { "type": "boolean", "enum": [true] }, "status": { "type": "string", "enum": ["live"] } } },
      "Readiness": { "type": "object", "required": ["ok", "status"], "properties": { "ok": { "type": "boolean" }, "status": { "type": "string", "enum": ["ready", "unready"] }, "checks": { "type": "object", "additionalProperties": true } } }
    },
    "headers": {
      "NativeSessionCookie": { "description": "Opaque native session cookie set or cleared by the server. Browsers must treat it as HttpOnly.", "schema": { "type": "string" } },
      "RetryAfter": { "description": "Whole seconds before the client should retry.", "schema": { "type": "integer", "minimum": 1 } }
    },
    "responses": {
      "BadRequest": { "description": "Malformed, ambiguous, or invalid request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorEnvelope" } } } },
      "Unauthorized": { "description": "Missing, invalid, expired, revoked, or unavailable credential.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorEnvelope" } } } },
      "Forbidden": { "description": "Authenticated principal denied by CSRF, transport, role, workspace, resource, or policy checks.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorEnvelope" } } } },
      "NotFound": { "description": "Unknown route/resource or a route/operation unavailable in this deployment profile.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorEnvelope" } } } },
      "RateLimited": { "description": "Rate/concurrency limit exceeded. Observe Retry-After when present.", "headers": { "Retry-After": { "$ref": "#/components/headers/RetryAfter" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorEnvelope" } } } },
      "PayloadTooLarge": { "description": "Request body exceeds the configured bound.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorEnvelope" } } } },
      "UnsupportedMediaType": { "description": "Content-Type is not accepted by this route.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorEnvelope" } } } },
      "Unavailable": { "description": "Service, storage, readiness, or dependency unavailable. Inspect retryable before retrying.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorEnvelope" } } } }
    }
  }
}
