{
  "openapi": "3.1.0",
  "info": {
    "title": "Platform base",
    "description": "The platform base API owns tenant registration, idempotency records, and audit evidence shared across platform APIs. The tenant registry is the global directory every row-level module shares. Idempotency keys record replay state for tenant-scoped writes. Audit logs preserve append-only operational evidence for cross-module actions.",
    "version": "1.0"
  },
  "tags": [
    {
      "name": "Audit log",
      "description": "An append-only tenant-scoped audit event. It records who attempted an action, what resource was touched, and whether the action succeeded."
    },
    {
      "name": "Idempotency key",
      "description": "A tenant-scoped replay record for one write route and idempotency key. Platform modules use this shape as the durable contract for replay detection and response reuse."
    },
    {
      "name": "Tenant",
      "description": "A global tenant registration shared by every platform4 module. It is tenantScoped:false because it defines the tenant space instead of belonging to one tenant."
    }
  ],
  "paths": {
    "/platform/v1/audit-log": {
      "post": {
        "operationId": "createAuditLog",
        "summary": "Record an audit event",
        "description": "Appends one audit event for a tenant-scoped action. `tenantRef` MUST reference an already-registered `tenant.id` (register via POST /v1/tenant first). Replays with the same Idempotency-Key return the stored response via the engine.\n\n> **Auth required:** a verified bearer token is required.",
        "tags": [
          "Audit log"
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "The idempotency key (max 128 chars). Optional — when present, the call is replay-protected; a completed replay returns the stored response at 200 with idempotency-replayed: true.",
            "schema": {
              "type": "string",
              "maxLength": 128
            }
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateAuditLogRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK (idempotent replay — the stored first response; idempotency-replayed: true).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuditLog"
                }
              }
            },
            "headers": {
              "idempotency-replayed": {
                "description": "true when this response is a stored idempotent replay (the hook did not run).",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true",
                    "false"
                  ]
                }
              },
              "Location": {
                "description": "URI of the created resource (detail route). Persisted on the idempotency row and re-served on replay.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "201": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuditLog"
                }
              }
            },
            "headers": {
              "idempotency-replayed": {
                "description": "true when this response is a stored idempotent replay (the hook did not run).",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true",
                    "false"
                  ]
                }
              },
              "Location": {
                "description": "URI of the created resource (detail route). Persisted on the idempotency row and re-served on replay.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Not Found.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "Conflict — an operation with this Idempotency-Key is already in progress (60s lock).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Entity — this Idempotency-Key was already used with a different request body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "428": {
            "description": "Precondition Required — this operation requires the Idempotency-Key header.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "501": {
            "description": "Not Implemented.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      },
      "get": {
        "operationId": "listAuditLogs",
        "summary": "List audit events",
        "description": "Lists audit events in reverse occurrence order, with optional actor, resource, and outcome filters.\n\n> **Auth required:** a verified bearer token is required.",
        "tags": [
          "Audit log"
        ],
        "parameters": [
          {
            "name": "actorId",
            "in": "query",
            "description": "Optional actor filter.",
            "schema": {
              "type": "string"
            },
            "x-filter": {
              "column": "actorId",
              "operator": "eq"
            }
          },
          {
            "name": "resourceType",
            "in": "query",
            "description": "Optional resource type filter.",
            "schema": {
              "type": "string"
            },
            "x-filter": {
              "column": "resourceType",
              "operator": "eq"
            }
          },
          {
            "name": "resourceId",
            "in": "query",
            "description": "Optional resource id filter.",
            "schema": {
              "type": "string"
            },
            "x-filter": {
              "column": "resourceId",
              "operator": "eq"
            }
          },
          {
            "name": "outcome",
            "in": "query",
            "description": "Optional outcome filter.",
            "schema": {
              "type": "string",
              "enum": [
                "allowed",
                "denied",
                "failed"
              ]
            },
            "x-filter": {
              "column": "outcome",
              "operator": "eq"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum number of items to return on this page (clamped server-side).",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Opaque pagination cursor — pass the previous page's `nextCursor` to fetch the next page.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "nextCursor"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AuditLog"
                      }
                    },
                    "nextCursor": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Cursor for the next page, or null when this is the last page."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Not Found.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "Conflict.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "501": {
            "description": "Not Implemented.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/platform/v1/audit-log/{id}": {
      "get": {
        "operationId": "getAuditLog",
        "summary": "Get an audit event",
        "description": "Returns a single audit event by id.\n\n> **Auth required:** a verified bearer token is required.",
        "tags": [
          "Audit log"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The audit event id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuditLog"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Problem (audit_log_not_found).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "Conflict.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "501": {
            "description": "Not Implemented.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/platform/v1/idempotency-key": {
      "post": {
        "operationId": "createIdempotencyKey",
        "summary": "Record an idempotency key",
        "description": "Creates one tenant-scoped idempotency replay record for a write route. This entity is the durable operator-facing contract; per-route write replays for platform creates themselves are guarded by the synthesized `idempotency_key` engine when callers supply Idempotency-Key.\n\n> **Auth required:** a verified bearer token is required.",
        "tags": [
          "Idempotency key"
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "The idempotency key (max 128 chars). Optional — when present, the call is replay-protected; a completed replay returns the stored response at 200 with idempotency-replayed: true.",
            "schema": {
              "type": "string",
              "maxLength": 128
            }
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateIdempotencyKeyRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK (idempotent replay — the stored first response; idempotency-replayed: true).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IdempotencyKey"
                }
              }
            },
            "headers": {
              "idempotency-replayed": {
                "description": "true when this response is a stored idempotent replay (the hook did not run).",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true",
                    "false"
                  ]
                }
              }
            }
          },
          "201": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IdempotencyKey"
                }
              }
            },
            "headers": {
              "idempotency-replayed": {
                "description": "true when this response is a stored idempotent replay (the hook did not run).",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true",
                    "false"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Bad Request.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Not Found.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "Conflict — an operation with this Idempotency-Key is already in progress (60s lock).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Entity — this Idempotency-Key was already used with a different request body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "428": {
            "description": "Precondition Required — this operation requires the Idempotency-Key header.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "501": {
            "description": "Not Implemented.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      },
      "get": {
        "operationId": "listIdempotencyKeys",
        "summary": "List idempotency keys",
        "description": "Lists idempotency replay records, optionally narrowed by route, operation, or state.\n\n> **Auth required:** a verified bearer token is required.",
        "tags": [
          "Idempotency key"
        ],
        "parameters": [
          {
            "name": "routeTemplate",
            "in": "query",
            "description": "Optional route template filter.",
            "schema": {
              "type": "string"
            },
            "x-filter": {
              "column": "routeTemplate",
              "operator": "eq"
            }
          },
          {
            "name": "operationId",
            "in": "query",
            "description": "Optional operationId filter.",
            "schema": {
              "type": "string"
            },
            "x-filter": {
              "column": "operationId",
              "operator": "eq"
            }
          },
          {
            "name": "key",
            "in": "query",
            "description": "Optional Idempotency-Key value filter (natural-key leg).",
            "schema": {
              "type": "string"
            },
            "x-filter": {
              "column": "key",
              "operator": "eq"
            }
          },
          {
            "name": "state",
            "in": "query",
            "description": "Optional replay state filter.",
            "schema": {
              "type": "string",
              "enum": [
                "in_progress",
                "completed",
                "failed"
              ]
            },
            "x-filter": {
              "column": "state",
              "operator": "eq"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum number of items to return on this page (clamped server-side).",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Opaque pagination cursor — pass the previous page's `nextCursor` to fetch the next page.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "nextCursor"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/IdempotencyKey"
                      }
                    },
                    "nextCursor": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Cursor for the next page, or null when this is the last page."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Not Found.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "Conflict.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "501": {
            "description": "Not Implemented.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/platform/v1/tenant": {
      "get": {
        "operationId": "listTenants",
        "summary": "List tenants",
        "description": "Lists the global tenant registry for operators and system services.\n\n> **Auth required:** a verified bearer token is required.",
        "tags": [
          "Tenant"
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "description": "Optional tenant status filter.",
            "schema": {
              "type": "string",
              "enum": [
                "active",
                "suspended",
                "closed"
              ]
            },
            "x-filter": {
              "column": "status",
              "operator": "eq"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum number of items to return on this page (clamped server-side).",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Opaque pagination cursor — pass the previous page's `nextCursor` to fetch the next page.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "nextCursor"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Tenant"
                      }
                    },
                    "nextCursor": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Cursor for the next page, or null when this is the last page."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Not Found.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "Conflict.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "501": {
            "description": "Not Implemented.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createTenant",
        "summary": "Register a tenant",
        "description": "Creates one global tenant registry row. Downstream modules and audit-log rows FK to this id; register the tenant before writing tenant-scoped evidence. Optimistic replays use the idempotency engine when an Idempotency-Key header is supplied.\n\n> **Auth required:** a verified bearer token is required.",
        "tags": [
          "Tenant"
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "The idempotency key (max 128 chars). Optional — when present, the call is replay-protected; a completed replay returns the stored response at 200 with idempotency-replayed: true.",
            "schema": {
              "type": "string",
              "maxLength": 128
            }
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateTenantRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK (idempotent replay — the stored first response; idempotency-replayed: true).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Tenant"
                }
              }
            },
            "headers": {
              "idempotency-replayed": {
                "description": "true when this response is a stored idempotent replay (the hook did not run).",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true",
                    "false"
                  ]
                }
              },
              "ETag": {
                "description": "The resource's current entity-tag (RFC 9110, quoted). Send it back in If-Match on the next write (optimistic concurrency).",
                "schema": {
                  "type": "string"
                }
              },
              "Location": {
                "description": "URI of the created resource (detail route). Persisted on the idempotency row and re-served on replay.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "201": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Tenant"
                }
              }
            },
            "headers": {
              "idempotency-replayed": {
                "description": "true when this response is a stored idempotent replay (the hook did not run).",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true",
                    "false"
                  ]
                }
              },
              "ETag": {
                "description": "The resource's current entity-tag (RFC 9110, quoted). Send it back in If-Match on the next write (optimistic concurrency).",
                "schema": {
                  "type": "string"
                }
              },
              "Location": {
                "description": "URI of the created resource (detail route). Persisted on the idempotency row and re-served on replay.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Not Found.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "Problem (tenant_already_exists).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Entity — this Idempotency-Key was already used with a different request body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "428": {
            "description": "Precondition Required — this operation requires the Idempotency-Key header.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "501": {
            "description": "Not Implemented.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/platform/v1/tenant/{id}": {
      "get": {
        "operationId": "getTenant",
        "summary": "Get a tenant",
        "description": "Returns one tenant registration by its stable tenant id.\n\n> **Auth required:** a verified bearer token is required.",
        "tags": [
          "Tenant"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The tenant id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Tenant"
                }
              }
            },
            "headers": {
              "ETag": {
                "description": "The resource's current entity-tag (RFC 9110, quoted). Send it back in If-Match on the next write (optimistic concurrency).",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Problem (tenant_not_found).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "Conflict.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "501": {
            "description": "Not Implemented.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "updateTenant",
        "summary": "Update a tenant",
        "description": "Updates mutable tenant registration fields. Optimistic concurrency requires the caller's `If-Match` value to match the current tenant version.\n\n> **Auth required:** a verified bearer token is required.",
        "tags": [
          "Tenant"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The tenant id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "description": "The resource's current ETag (from the last GET/write response), quoted per RFC 9110. REQUIRED — absent returns 428; a stale ETag returns 412 (refetch and retry). Send `*` to overwrite unconditionally.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateTenantRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Tenant"
                }
              }
            },
            "headers": {
              "ETag": {
                "description": "The resource's current entity-tag (RFC 9110, quoted). Send it back in If-Match on the next write (optimistic concurrency).",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Problem (tenant_not_found).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "Conflict.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "412": {
            "description": "Problem (precondition_failed).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "428": {
            "description": "Precondition Required — this write requires the If-Match header (send the resource's ETag).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "501": {
            "description": "Not Implemented.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/platform/v1/tenant/sandbox": {
      "post": {
        "operationId": "provisionSandboxTenant",
        "summary": "Provision a sandbox tenant",
        "description": "Provisions a sandbox tenant for vendor onboarding. Creates the global tenant registry row when absent, or returns the existing row when the same tenantId+slug is re-posted (deterministic without Idempotency-Key or replay headers). The response includes durable seedContract fixture ids for sandbox quickstart; this operation does not materialize oneroster or content rows. Conflicting identity or slug data fails closed.\n\n> **Auth required:** a verified bearer token is required.",
        "tags": [
          "Tenant"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "tenantId": {
                    "type": "string",
                    "format": "uuid",
                    "description": "Client-supplied stable tenant id (JWT tenant claim)."
                  },
                  "slug": {
                    "type": "string",
                    "pattern": "^[a-z0-9][a-z0-9-]*[a-z0-9]$",
                    "minLength": 3,
                    "maxLength": 80,
                    "description": "Human-stable tenant slug (immutable identity with tenantId)."
                  },
                  "displayName": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 160,
                    "description": "Human-readable tenant name."
                  },
                  "status": {
                    "type": "string",
                    "enum": [
                      "active",
                      "suspended",
                      "closed"
                    ],
                    "description": "Initial operational status (typically active)."
                  },
                  "dataRegion": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 40,
                    "description": "Deployment or residency region."
                  },
                  "createdBy": {
                    "type": "string",
                    "minLength": 1,
                    "description": "Principal or automation that created the tenant registration."
                  }
                },
                "required": [
                  "tenantId",
                  "slug",
                  "displayName",
                  "status",
                  "createdBy"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "tenantId": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "slug": {
                      "type": "string",
                      "pattern": "^[a-z0-9][a-z0-9-]*[a-z0-9]$",
                      "minLength": 3,
                      "maxLength": 80
                    },
                    "displayName": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 160
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "active",
                        "suspended",
                        "closed"
                      ]
                    },
                    "dataRegion": {
                      "type": "string",
                      "minLength": 2,
                      "maxLength": 40
                    },
                    "createdBy": {
                      "type": "string",
                      "minLength": 1
                    },
                    "createdAt": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "updatedAt": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "seedContract": {
                      "type": "object",
                      "properties": {
                        "orgSourcedId": {
                          "type": "string",
                          "const": "org-sandbox-quickstart",
                          "description": "Sandbox quickstart oneroster org sourcedId."
                        },
                        "teacherSourcedId": {
                          "type": "string",
                          "const": "user-sandbox-teacher",
                          "description": "Sandbox quickstart teacher user sourcedId."
                        },
                        "studentSourcedId": {
                          "type": "string",
                          "const": "user-sandbox-student",
                          "description": "Sandbox quickstart student user sourcedId."
                        },
                        "contentId": {
                          "type": "string",
                          "const": "c0ffeeee-0000-4000-8000-000000000001",
                          "format": "uuid",
                          "description": "Sandbox quickstart content/qti artifact id."
                        }
                      },
                      "required": [
                        "orgSourcedId",
                        "teacherSourcedId",
                        "studentSourcedId",
                        "contentId"
                      ],
                      "description": "Stable sandbox quickstart fixture ids. Callers use these when seeding related module data; platform does not write foreign-module seed rows on this operation.",
                      "additionalProperties": false
                    }
                  },
                  "required": [
                    "tenantId",
                    "slug",
                    "displayName",
                    "status",
                    "createdBy",
                    "createdAt",
                    "updatedAt",
                    "seedContract"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "400": {
            "description": "Bad Request.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Not Found.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "Problem (tenant_already_exists).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "501": {
            "description": "Not Implemented.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "AuditLog": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Stable audit event identifier.",
            "readOnly": true
          },
          "tenantRef": {
            "type": "object",
            "description": "A OneRoster GUIDRef to a tenant — the referenced resource's sourcedId, its type, and a dereferenceable href. On write, either this object (its sourcedId is used) or the bare sourcedId string is accepted.",
            "required": [
              "sourcedId",
              "type"
            ],
            "properties": {
              "href": {
                "type": "string",
                "description": "The dereferenceable URL of the referenced resource."
              },
              "sourcedId": {
                "type": "string",
                "description": "The sourcedId of the referenced resource."
              },
              "type": {
                "type": "string",
                "const": "tenant",
                "description": "The referenced resource type."
              }
            }
          },
          "occurredAt": {
            "type": "string",
            "format": "date-time",
            "description": "Instant when the audited action occurred."
          },
          "actorId": {
            "type": "string",
            "minLength": 1,
            "description": "Principal, service, or automation that attempted the action."
          },
          "actorType": {
            "type": "string",
            "enum": [
              "user",
              "service",
              "agent",
              "system"
            ],
            "description": "Kind of principal that attempted the action."
          },
          "action": {
            "type": "string",
            "minLength": 1,
            "maxLength": 160,
            "description": "Operation or domain action being audited."
          },
          "resourceType": {
            "type": "string",
            "minLength": 1,
            "maxLength": 160,
            "description": "Module-qualified resource type touched by the action."
          },
          "resourceId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 240,
            "description": "Resource identifier as seen by the audited module."
          },
          "outcome": {
            "type": "string",
            "enum": [
              "allowed",
              "denied",
              "failed"
            ],
            "description": "Final authorization or execution outcome for the action."
          },
          "requestId": {
            "type": "string",
            "maxLength": 160,
            "description": "Request correlation id, when the action came from an HTTP or job boundary."
          },
          "idempotencyKey": {
            "type": "string",
            "maxLength": 128,
            "description": "Idempotency-Key header associated with the action, when one guarded the write."
          },
          "metadata": {
            "type": "object",
            "description": "Additional structured audit details that do not belong in first-class indexed fields."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "readOnly": true,
            "description": "Server-managed row-creation timestamp (RFC 3339). Read-only — never accepted on create or update."
          }
        },
        "required": [
          "id",
          "tenantRef",
          "occurredAt",
          "actorId",
          "action",
          "resourceType",
          "resourceId",
          "outcome",
          "createdAt"
        ]
      },
      "IdempotencyKey": {
        "type": "object",
        "properties": {
          "routeTemplate": {
            "type": "string",
            "minLength": 1,
            "maxLength": 240,
            "description": "Stable route template for the operation guarded by this key."
          },
          "operationId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120,
            "description": "OpenAPI operationId for the write path guarded by this key."
          },
          "key": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128,
            "description": "Client-supplied Idempotency-Key header value for this operation."
          },
          "requestHash": {
            "type": "string",
            "pattern": "^sha256:[0-9a-f]{64}$",
            "description": "Canonical SHA-256 request hash used to reject key reuse with a different request body."
          },
          "state": {
            "type": "string",
            "enum": [
              "in_progress",
              "completed",
              "failed"
            ],
            "description": "Replay lifecycle state. Completed records can return their stored response; in-progress records protect an active write."
          },
          "responseStatus": {
            "type": "integer",
            "minimum": 100,
            "maximum": 599,
            "description": "HTTP status code stored after a completed write, when a response is available for replay."
          },
          "responseBody": {
            "oneOf": [
              {
                "type": "object"
              },
              {
                "type": "array"
              },
              {
                "type": "string"
              },
              {
                "type": "number"
              },
              {
                "type": "boolean"
              }
            ],
            "description": "Any non-null JSON response body stored for a completed replay. Absence means the first response had no body."
          },
          "responseHeaders": {
            "type": "object",
            "description": "Response headers that must be replayed with the stored body."
          },
          "lockedUntil": {
            "type": "string",
            "format": "date-time",
            "description": "Instant until which an in-progress claim blocks another request with the same key."
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time",
            "description": "Instant after which the replay record may be swept and the key may be reused."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "readOnly": true,
            "description": "Server-managed row-creation timestamp (RFC 3339). Read-only — never accepted on create or update."
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "readOnly": true,
            "description": "Server-managed last-update timestamp (RFC 3339). Read-only — never accepted on create or update."
          }
        },
        "required": [
          "routeTemplate",
          "operationId",
          "key",
          "requestHash",
          "state",
          "expiresAt",
          "createdAt",
          "updatedAt"
        ]
      },
      "Tenant": {
        "type": "object",
        "properties": {
          "tenantId": {
            "type": "string",
            "format": "uuid",
            "description": "Stable tenant identifier. Client-supplied on create (matches JWT tenant claims). This is the global key other modules carry as their row-level tenant claim."
          },
          "slug": {
            "type": "string",
            "pattern": "^[a-z0-9][a-z0-9-]*[a-z0-9]$",
            "minLength": 3,
            "maxLength": 80,
            "description": "Human-stable tenant slug used in operator tooling and documentation."
          },
          "displayName": {
            "type": "string",
            "minLength": 1,
            "maxLength": 160,
            "description": "Human-readable tenant name shown in administrative surfaces."
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "suspended",
              "closed"
            ],
            "description": "Operational status for the tenant. Suspended tenants remain registered but should not accept ordinary writes.",
            "default": "active"
          },
          "dataRegion": {
            "type": "string",
            "minLength": 2,
            "maxLength": 40,
            "description": "Deployment or residency region that owns the tenant's primary data."
          },
          "createdBy": {
            "type": "string",
            "minLength": 1,
            "description": "Principal or automation that created the tenant registration."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "readOnly": true,
            "description": "Server-managed row-creation timestamp (RFC 3339). Read-only — never accepted on create or update."
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "readOnly": true,
            "description": "Server-managed last-update timestamp (RFC 3339). Read-only — never accepted on create or update."
          }
        },
        "required": [
          "tenantId",
          "slug",
          "displayName",
          "status",
          "createdBy",
          "createdAt",
          "updatedAt"
        ]
      },
      "CreateAuditLogRequest": {
        "type": "object",
        "description": "Create-AuditLog request body (readOnly/server-managed fields excluded).",
        "required": [
          "tenantRef",
          "occurredAt",
          "actorId",
          "action",
          "resourceType",
          "resourceId",
          "outcome"
        ],
        "additionalProperties": false,
        "properties": {
          "tenantRef": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "object",
                "description": "A OneRoster GUIDRef to a tenant — the referenced resource's sourcedId, its type, and a dereferenceable href. On write, either this object (its sourcedId is used) or the bare sourcedId string is accepted.",
                "required": [
                  "sourcedId",
                  "type"
                ],
                "properties": {
                  "href": {
                    "type": "string",
                    "description": "The dereferenceable URL of the referenced resource."
                  },
                  "sourcedId": {
                    "type": "string",
                    "description": "The sourcedId of the referenced resource."
                  },
                  "type": {
                    "type": "string",
                    "const": "tenant",
                    "description": "The referenced resource type."
                  }
                }
              }
            ],
            "description": "A OneRoster GUIDRef to a tenant, or the bare sourcedId string — both write the scalar tenantRef."
          },
          "occurredAt": {
            "type": "string",
            "format": "date-time",
            "description": "Instant when the audited action occurred."
          },
          "actorId": {
            "type": "string",
            "minLength": 1,
            "description": "Principal, service, or automation that attempted the action."
          },
          "actorType": {
            "type": "string",
            "enum": [
              "user",
              "service",
              "agent",
              "system"
            ],
            "description": "Kind of principal that attempted the action."
          },
          "action": {
            "type": "string",
            "minLength": 1,
            "maxLength": 160,
            "description": "Operation or domain action being audited."
          },
          "resourceType": {
            "type": "string",
            "minLength": 1,
            "maxLength": 160,
            "description": "Module-qualified resource type touched by the action."
          },
          "resourceId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 240,
            "description": "Resource identifier as seen by the audited module."
          },
          "outcome": {
            "type": "string",
            "enum": [
              "allowed",
              "denied",
              "failed"
            ],
            "description": "Final authorization or execution outcome for the action."
          },
          "requestId": {
            "type": "string",
            "maxLength": 160,
            "description": "Request correlation id, when the action came from an HTTP or job boundary."
          },
          "idempotencyKey": {
            "type": "string",
            "maxLength": 128,
            "description": "Idempotency-Key header associated with the action, when one guarded the write."
          },
          "metadata": {
            "type": "object",
            "description": "Additional structured audit details that do not belong in first-class indexed fields."
          }
        }
      },
      "CreateIdempotencyKeyRequest": {
        "type": "object",
        "description": "Create-IdempotencyKey request body (readOnly/server-managed fields excluded).",
        "required": [
          "routeTemplate",
          "operationId",
          "key",
          "requestHash",
          "state",
          "expiresAt"
        ],
        "additionalProperties": false,
        "properties": {
          "routeTemplate": {
            "type": "string",
            "minLength": 1,
            "maxLength": 240,
            "description": "Stable route template for the operation guarded by this key."
          },
          "operationId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120,
            "description": "OpenAPI operationId for the write path guarded by this key."
          },
          "key": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128,
            "description": "Client-supplied Idempotency-Key header value for this operation."
          },
          "requestHash": {
            "type": "string",
            "pattern": "^sha256:[0-9a-f]{64}$",
            "description": "Canonical SHA-256 request hash used to reject key reuse with a different request body."
          },
          "state": {
            "type": "string",
            "enum": [
              "in_progress",
              "completed",
              "failed"
            ],
            "description": "Replay lifecycle state. Completed records can return their stored response; in-progress records protect an active write."
          },
          "responseStatus": {
            "type": "integer",
            "minimum": 100,
            "maximum": 599,
            "description": "HTTP status code stored after a completed write, when a response is available for replay."
          },
          "responseBody": {
            "oneOf": [
              {
                "type": "object"
              },
              {
                "type": "array"
              },
              {
                "type": "string"
              },
              {
                "type": "number"
              },
              {
                "type": "boolean"
              }
            ],
            "description": "Any non-null JSON response body stored for a completed replay. Absence means the first response had no body."
          },
          "responseHeaders": {
            "type": "object",
            "description": "Response headers that must be replayed with the stored body."
          },
          "lockedUntil": {
            "type": "string",
            "format": "date-time",
            "description": "Instant until which an in-progress claim blocks another request with the same key."
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time",
            "description": "Instant after which the replay record may be swept and the key may be reused."
          }
        }
      },
      "CreateTenantRequest": {
        "type": "object",
        "description": "Create-Tenant request body (readOnly/server-managed fields excluded).",
        "required": [
          "tenantId",
          "slug",
          "displayName",
          "status",
          "createdBy"
        ],
        "additionalProperties": false,
        "properties": {
          "tenantId": {
            "type": "string",
            "format": "uuid",
            "description": "Stable tenant identifier. Client-supplied on create (matches JWT tenant claims). This is the global key other modules carry as their row-level tenant claim."
          },
          "slug": {
            "type": "string",
            "pattern": "^[a-z0-9][a-z0-9-]*[a-z0-9]$",
            "minLength": 3,
            "maxLength": 80,
            "description": "Human-stable tenant slug used in operator tooling and documentation."
          },
          "displayName": {
            "type": "string",
            "minLength": 1,
            "maxLength": 160,
            "description": "Human-readable tenant name shown in administrative surfaces."
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "suspended",
              "closed"
            ],
            "description": "Operational status for the tenant. Suspended tenants remain registered but should not accept ordinary writes.",
            "default": "active"
          },
          "dataRegion": {
            "type": "string",
            "minLength": 2,
            "maxLength": 40,
            "description": "Deployment or residency region that owns the tenant's primary data."
          },
          "createdBy": {
            "type": "string",
            "minLength": 1,
            "description": "Principal or automation that created the tenant registration."
          }
        }
      },
      "UpdateTenantRequest": {
        "type": "object",
        "description": "Update-Tenant request body (partial — all fields optional; readOnly + immutable fields excluded; null clears a nullable column).",
        "additionalProperties": false,
        "properties": {
          "displayName": {
            "type": "string",
            "minLength": 1,
            "maxLength": 160,
            "description": "Human-readable tenant name shown in administrative surfaces."
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "suspended",
              "closed"
            ],
            "description": "Operational status for the tenant. Suspended tenants remain registered but should not accept ordinary writes.",
            "default": "active"
          },
          "dataRegion": {
            "type": [
              "string",
              "null"
            ],
            "minLength": 2,
            "maxLength": 40,
            "description": "Deployment or residency region that owns the tenant's primary data."
          }
        }
      },
      "Problem": {
        "type": "object",
        "description": "RFC 7807 problem details.",
        "properties": {
          "type": {
            "type": "string",
            "format": "uri",
            "description": "A URI identifying the problem type."
          },
          "title": {
            "type": "string",
            "description": "A short, human-readable summary of the problem."
          },
          "status": {
            "type": "integer",
            "description": "The HTTP status code."
          },
          "detail": {
            "type": "string",
            "description": "A human-readable explanation specific to this occurrence."
          },
          "instance": {
            "type": "string",
            "format": "uri",
            "description": "A URI identifying this occurrence."
          }
        },
        "required": [
          "title",
          "status"
        ]
      }
    },
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT"
      }
    }
  },
  "servers": [
    {
      "url": "https://platform.platform4.alphaschool.dev"
    }
  ]
}
