{"openapi":"3.0.0","info":{"title":"Centrali IAM Service API","version":"5.1.2","description":"API documentation for the Centrali IAM Service - Authentication, authorization, and identity management.","contact":{"name":"Centrali Support"}},"servers":[{"url":"https://auth.centrali.io/","description":"IAM Service"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"JWT token obtained from the IAM service"},"oauth2":{"type":"oauth2","description":"OAuth 2.0 authorization","flows":{"authorizationCode":{"authorizationUrl":"/auth","tokenUrl":"/token","scopes":{"openid":"OpenID Connect scope","profile":"User profile information","email":"User email address","offline_access":"Refresh token access"}}}}},"schemas":{"Error":{"type":"object","required":["error","message","status","timestamp","path"],"properties":{"error":{"type":"string","example":"UNAUTHORIZED","description":"Machine-readable error code"},"message":{"type":"string","example":"Invalid credentials","description":"Human-readable error message"},"status":{"type":"integer","example":401,"description":"HTTP status code"},"timestamp":{"type":"string","format":"date-time","example":"2026-03-02T10:00:00.000Z"},"path":{"type":"string","example":"/iam/auth/login","description":"Request path"},"requestId":{"type":"string","description":"Optional request ID for tracing"}}},"User":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"name":{"type":"string"},"avatar_url":{"type":"string","format":"uri"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"ServiceAccount":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"client_id":{"type":"string"},"description":{"type":"string"},"workspace_slug":{"type":"string"},"created_at":{"type":"string","format":"date-time"}}},"Permission":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"action":{"type":"string","enum":["create","read","update","delete","admin"]},"resource_type":{"type":"string"},"resource_id":{"type":"string"},"workspace_slug":{"type":"string"}}},"Role":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string"},"permissions":{"type":"array","items":{"$ref":"#/components/schemas/Permission"}},"workspace_slug":{"type":"string"}}},"TokenResponse":{"type":"object","properties":{"access_token":{"type":"string"},"token_type":{"type":"string","example":"Bearer"},"expires_in":{"type":"integer","example":3600},"refresh_token":{"type":"string"},"id_token":{"type":"string"}}},"ClaimMapping":{"type":"object","required":["attribute","jwtPath"],"properties":{"attribute":{"type":"string","description":"Attribute name used in policies (will be prefixed with ext_)"},"jwtPath":{"type":"string","description":"Path to extract from JWT (dot notation for nested)"},"required":{"type":"boolean","default":false},"defaultValue":{"oneOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"array","items":{"type":"string"}}]},"transform":{"type":"string","enum":["lowercase","uppercase","string","boolean","array"]}}},"ExternalAuthProvider":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"workspaceSlug":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"providerType":{"type":"string","enum":["oidc","clerk","auth0","keycloak","okta","custom"]},"issuer":{"type":"string","format":"uri"},"jwksUrl":{"type":"string","format":"uri"},"allowedAudiences":{"type":"array","items":{"type":"string"}},"clockSkewSeconds":{"type":"integer"},"allowedAlgorithms":{"type":"array","items":{"type":"string"}},"claimMappings":{"type":"array","items":{"$ref":"#/components/schemas/ClaimMapping"}},"allowedOrigins":{"type":"array","items":{"type":"string"}},"isActive":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}}}},"security":[{"bearerAuth":[]}],"paths":{"/workspace/{workspaceSlug}/api/v1/access/allowed-user-attributes":{"get":{"summary":"List all allowed user attributes","tags":["Allowed User Attributes"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"},"description":"Workspace identifier"}],"responses":{"200":{"description":"List of allowed user attributes","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"type":{"type":"string"}}}}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"summary":"Create a new allowed user attribute","tags":["Allowed User Attributes"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","type"],"properties":{"name":{"type":"string"},"type":{"type":"string"}}}}}},"responses":{"201":{"description":"Attribute created successfully"},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/workspace/{workspaceSlug}/api/v1/access/allowed-user-attributes/{id}":{"get":{"summary":"Get a specific allowed user attribute","tags":["Allowed User Attributes"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Attribute details"},"404":{"description":"Attribute not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"summary":"Update an allowed user attribute","tags":["Allowed User Attributes"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"type":{"type":"string"}}}}}},"responses":{"200":{"description":"Attribute updated successfully"},"404":{"description":"Attribute not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"summary":"Partially update an allowed user attribute","tags":["Allowed User Attributes"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"type":{"type":"string"}}}}}},"responses":{"200":{"description":"Attribute updated successfully"},"404":{"description":"Attribute not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"summary":"Delete an allowed user attribute","tags":["Allowed User Attributes"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Attribute deleted successfully"},"404":{"description":"Attribute not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/workspace/{workspaceSlug}/api/v1/access/resources":{"get":{"summary":"List all resources","tags":["Resources"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of resources"}}},"post":{"summary":"Create a new resource","tags":["Resources"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","type"],"properties":{"name":{"type":"string"},"type":{"type":"string"},"description":{"type":"string"}}}}}},"responses":{"201":{"description":"Resource created successfully"}}}},"/workspace/{workspaceSlug}/api/v1/access/resources/{id}":{"get":{"summary":"Get a specific resource","tags":["Resources"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Resource details"},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"summary":"Update a resource","tags":["Resources"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"type":{"type":"string"},"description":{"type":"string"}}}}}},"responses":{"200":{"description":"Resource updated successfully"}}},"patch":{"summary":"Partially update a resource","tags":["Resources"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"description":"Resource updated successfully"}}},"delete":{"summary":"Delete a resource","tags":["Resources"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Resource deleted successfully"}}}},"/workspace/{workspaceSlug}/api/v1/access/resources/{resourceName}/context-schema":{"get":{"summary":"Get context schema for a resource","tags":["Permission Introspection"],"description":"Returns the schema of context attributes available for policy evaluation\non the specified resource. Useful for building policies and simulating access.\n","parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"resourceName","required":true,"schema":{"type":"string"},"description":"Resource name (e.g., \"records\", \"workspace::users\")"},{"in":"query","name":"action","schema":{"type":"string"},"description":"Filter schema for specific action"}],"responses":{"200":{"description":"Context schema","content":{"application/json":{"schema":{"type":"object","properties":{"resource":{"type":"string"},"actions":{"type":"array","items":{"type":"string"}},"contextSchema":{"type":"object","additionalProperties":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"type":{"type":"string"},"description":{"type":"string"},"source":{"type":"string"},"example":{"type":"string"}}}}}}}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/workspace/{workspaceSlug}/api/v1/access/permissions":{"get":{"summary":"List all permissions","tags":["Permissions"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of permissions","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Permission"}}}}}}}}},"post":{"summary":"Create a new permission","tags":["Permissions"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["action","resource_type"],"properties":{"action":{"type":"string","enum":["create","read","update","delete","admin"]},"resource_type":{"type":"string"},"resource_id":{"type":"string"},"description":{"type":"string"}}}}}},"responses":{"201":{"description":"Permission created successfully"}}}},"/workspace/{workspaceSlug}/api/v1/access/permissions/{id}":{"get":{"summary":"Get a specific permission","tags":["Permissions"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Permission details"},"404":{"description":"Permission not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"summary":"Update a permission","tags":["Permissions"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"description":"Permission updated successfully"}}},"patch":{"summary":"Partially update a permission","tags":["Permissions"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"description":"Permission updated successfully"}}},"delete":{"summary":"Delete a permission","tags":["Permissions"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Permission deleted successfully"}}}},"/workspace/{workspaceSlug}/api/v1/access/policies":{"get":{"summary":"List all policies","tags":["Policies"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of policies"}}},"post":{"summary":"Create a new policy","tags":["Policies"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","specification"],"properties":{"name":{"type":"string"},"description":{"type":"string"},"specification":{"type":"object","description":"Policy specification in Cedar format"}}}}}},"responses":{"201":{"description":"Policy created successfully"}}}},"/workspace/{workspaceSlug}/api/v1/access/policies/validate":{"post":{"summary":"Validate a policy specification","tags":["Policies"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["specification"],"properties":{"specification":{"type":"object","description":"Policy specification to validate"}}}}}},"responses":{"200":{"description":"Validation result","content":{"application/json":{"schema":{"type":"object","properties":{"valid":{"type":"boolean"},"errors":{"type":"array","items":{"type":"string"}}}}}}}}}},"/workspace/{workspaceSlug}/api/v1/access/policies/{id}":{"get":{"summary":"Get a specific policy","tags":["Policies"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Policy details"},"404":{"description":"Policy not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"summary":"Update a policy","tags":["Policies"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"description":"Policy updated successfully"}}},"patch":{"summary":"Partially update a policy","tags":["Policies"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"description":"Policy updated successfully"}}},"delete":{"summary":"Delete a policy","tags":["Policies"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Policy deleted successfully"}}}},"/workspace/{workspaceSlug}/api/v1/access/evaluate":{"post":{"summary":"Evaluate access for a principal against a resource","tags":["Access Evaluation"],"description":"Evaluates whether a principal (user or service account) has access to perform an action on a resource","parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["principal","action","resource"],"properties":{"principal":{"type":"object","properties":{"type":{"type":"string","enum":["user","service_account"]},"id":{"type":"string"}}},"action":{"type":"string","enum":["create","read","update","delete","admin"]},"resource":{"type":"object","properties":{"type":{"type":"string"},"id":{"type":"string"}}},"context":{"type":"object","description":"Additional context for evaluation"}}}}}},"responses":{"200":{"description":"Access evaluation result","content":{"application/json":{"schema":{"type":"object","properties":{"allowed":{"type":"boolean"},"reason":{"type":"string"}}}}}}}}},"/workspace/{workspaceSlug}/api/v1/access/evaluate/debug":{"post":{"summary":"Evaluate access with optional principal impersonation and debug info","tags":["Permission Introspection"],"description":"Enhanced access evaluation supporting:\n- Evaluating as a specific service account (principal)\n- Debug mode returning evaluation context and \"why\" classification\n- Trace mode returning step-by-step evaluation details\n\nRequires `security:debug` permission on `workspace::service-accounts` when using principal parameter.\n","parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["resource","resourceCategory","action"],"properties":{"resource":{"type":"string","description":"Resource name to evaluate (e.g., \"workspace::users\")"},"resourceCategory":{"type":"string","description":"Resource category (e.g., \"workspace\")"},"action":{"type":"string","description":"Action to evaluate (e.g., \"create\", \"delete\")"},"principal":{"type":"object","description":"Optional principal to evaluate as","properties":{"type":{"type":"string","enum":["service_account"]},"id":{"type":"integer","description":"Service account ID"}}},"context":{"type":"object","description":"Optional context overrides","properties":{"ipAddress":{"type":"string"},"requestMetadata":{"type":"object"},"timeOverride":{"type":"string"}}},"debug":{"type":"boolean","default":false,"description":"Return evaluation context and \"why\" information"},"includeTrace":{"type":"boolean","default":false,"description":"Return step-by-step evaluation trace"}}}}}},"responses":{"200":{"description":"Evaluation result","content":{"application/json":{"schema":{"type":"object","properties":{"decision":{"type":"string","enum":["Allow","Deny"]},"evaluation_context":{"type":"object","description":"All variables used in evaluation (when debug=true)"},"why":{"type":"object","properties":{"classification":{"type":"string","enum":["allowed","resource_not_found","no_permission_for_action","policy_denied"]},"message":{"type":"string"}}},"trace":{"type":"array","description":"Step-by-step evaluation trace (when includeTrace=true)"}}}}}},"403":{"description":"Missing security:debug permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Service account not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/workspace/{workspaceSlug}/api/v1/access/evaluate/batch":{"post":{"summary":"Batch evaluate multiple resource/action pairs for a service account","tags":["Permission Introspection"],"description":"Evaluates multiple resource/action combinations in a single request.\nUseful for permission scanning and building access matrices.\n\nRequires `security:debug` permission on `workspace::service-accounts`.\n","parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["principal"],"properties":{"principal":{"type":"object","required":["type","id"],"properties":{"type":{"type":"string","enum":["service_account"]},"id":{"type":"integer","description":"Service account ID"}}},"resourceNames":{"type":"array","items":{"type":"string"},"description":"Resource names to evaluate (null = all resources)"},"actions":{"type":"array","items":{"type":"string"},"description":"Actions to evaluate (null = all actions per resource)"},"context":{"type":"object","properties":{"ipAddress":{"type":"string"},"requestMetadata":{"type":"object"}}},"debug":{"type":"boolean","default":true},"pagination":{"type":"object","properties":{"offset":{"type":"integer","default":0},"limit":{"type":"integer","default":50,"maximum":100}}}}}}}},"responses":{"200":{"description":"Batch evaluation results","content":{"application/json":{"schema":{"type":"object","properties":{"results":{"type":"array","items":{"type":"object","properties":{"resource":{"type":"string"},"resourceCategory":{"type":"string"},"action":{"type":"string"},"decision":{"type":"string","enum":["Allow","Deny","Error"]},"evaluation_context":{"type":"object"},"why":{"type":"object"}}}},"serviceAccount":{"type":"object"},"pagination":{"type":"object","properties":{"offset":{"type":"integer"},"limit":{"type":"integer"},"total":{"type":"integer"},"hasMore":{"type":"boolean"}}}}}}}},"403":{"description":"Missing security:debug permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Service account not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/workspace/{workspaceSlug}/api/v1/access/permissions/remediation/generate":{"post":{"summary":"Generate remediation options for granting access","tags":["Permission Introspection"],"description":"Analyzes why a service account lacks access and generates options to fix it.\nOptions include: assigning an existing role, joining a group, or creating a minimal policy.\n\nRequires `security:debug` permission on `workspace::service-accounts`.\n","parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["targetType","targetId","resource","resourceCategory","actions"],"properties":{"targetType":{"type":"string","enum":["service_account"]},"targetId":{"type":"integer","description":"Service account ID"},"resource":{"type":"string","description":"Resource name (e.g., \"workspace::users\")"},"resourceCategory":{"type":"string","description":"Resource category (e.g., \"workspace\")"},"actions":{"type":"array","items":{"type":"string"},"description":"Actions to grant access for"}}}}}},"responses":{"200":{"description":"Remediation options","content":{"application/json":{"schema":{"type":"object","properties":{"targetInfo":{"type":"object"},"requestedAccess":{"type":"object"},"options":{"type":"array","items":{"type":"object","properties":{"optionId":{"type":"string"},"type":{"type":"string","enum":["role_assignment","group_assignment","create_new"]},"description":{"type":"string"},"effort":{"type":"string","enum":["low","medium","high"]},"recommended":{"type":"boolean"},"steps":{"type":"array"},"sideEffects":{"type":"array"}}}},"currentAccessStatus":{"type":"object"}}}}}},"403":{"description":"Missing security:debug permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Service account not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/workspace/{workspaceSlug}/api/v1/access/permissions/remediation/preview":{"post":{"summary":"Preview changes that would be made by applying a remediation option","tags":["Permission Introspection"],"description":"Returns a preview of what resources would be created/modified\nwithout actually making any changes.\n\nRequires `security:debug` permission on `workspace::service-accounts`.\n","parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["targetType","targetId","resource","resourceCategory","actions","optionId","option"],"properties":{"targetType":{"type":"string","enum":["service_account"]},"targetId":{"type":"integer"},"resource":{"type":"string"},"resourceCategory":{"type":"string"},"actions":{"type":"array","items":{"type":"string"}},"optionId":{"type":"string"},"option":{"type":"object","description":"The complete remediation option object"}}}}}},"responses":{"200":{"description":"Preview of changes","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["preview"]},"wouldCreate":{"type":"array"},"wouldModify":{"type":"array"},"summary":{"type":"array","items":{"type":"string"}}}}}}}}}},"/workspace/{workspaceSlug}/api/v1/access/permissions/remediation/apply":{"post":{"summary":"Apply a remediation option to grant access","tags":["Permission Introspection"],"description":"Applies the selected remediation option, creating policies/permissions\nor assigning roles/groups as needed. Verifies access after applying.\n\nRequires `security:debug` permission on `workspace::service-accounts`.\n","parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["targetType","targetId","resource","resourceCategory","actions","optionId","option"],"properties":{"targetType":{"type":"string","enum":["service_account"]},"targetId":{"type":"integer"},"resource":{"type":"string"},"resourceCategory":{"type":"string"},"actions":{"type":"array","items":{"type":"string"}},"optionId":{"type":"string"},"option":{"type":"object","description":"The complete remediation option object"},"dryRun":{"type":"boolean","default":false,"description":"If true, returns preview instead of applying"}}}}}},"responses":{"200":{"description":"Remediation result","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["success","partial","failed"]},"created":{"type":"array"},"modified":{"type":"array"},"verification":{"type":"object","properties":{"testResult":{"type":"string","enum":["Allow","Deny","Error"]},"message":{"type":"string"},"testedActions":{"type":"array"}}},"errors":{"type":"array","items":{"type":"string"}}}}}}}}}},"/workspace/{workspaceSlug}/api/v1/access/functions":{"get":{"summary":"List available policy functions","tags":["Functions"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of available functions"}}}},"/workspace/{workspaceSlug}/api/v1/access/functions/names":{"get":{"summary":"Get function names only","tags":["Functions"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of function names"}}}},"/workspace/{workspaceSlug}/api/v1/access/allowed-attributes":{"get":{"summary":"List allowed policy attributes","tags":["Allowed Attributes"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of allowed attributes"}}}},"/workspace/{workspaceSlug}/api/v1/access/allowed-attributes/names":{"get":{"summary":"Get allowed attribute names only","tags":["Allowed Attributes"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of allowed attribute names"}}}},"/workspace/{workspaceSlug}/api/v1/access/generative-operations":{"get":{"summary":"Get generative AI operations for policy creation","tags":["Generative Operations"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of generative operations"}}}},"/workspace/{workspaceSlug}/api/v1/access/generative-operations/names":{"get":{"summary":"Get generative operation names only","tags":["Generative Operations"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of generative operation names"}}}},"/workspace/{workspaceSlug}/api/v1/access/permissions/structure/{structureSlug}/access":{"get":{"summary":"Get record access permissions for a specific structure","tags":["Permission Introspection"],"description":"Returns all permissions that grant access to records in a specific structure.\nShows which groups have access, what actions they can perform, and whether\naccess is structure-specific or applies to all structures.\n\nRequires `security:debug` permission on `workspace::service-accounts`.\n","parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"structureSlug","required":true,"schema":{"type":"string"},"description":"Structure slug (e.g., \"orders\", \"customers\")"}],"responses":{"200":{"description":"Structure record access information","content":{"application/json":{"schema":{"type":"object","properties":{"structureSlug":{"type":"string"},"resource":{"type":"string"},"summary":{"type":"object","properties":{"totalGroups":{"type":"integer"},"totalPermissions":{"type":"integer"},"structureSpecificPermissions":{"type":"integer"},"broadPermissions":{"type":"integer"}}},"accessByAction":{"type":"array","items":{"type":"object","properties":{"action":{"type":"string"},"groupsWithAccess":{"type":"array","items":{"type":"string"}},"hasStructureSpecificAccess":{"type":"boolean"},"hasBroadAccess":{"type":"boolean"}}}},"allGroups":{"type":"array","items":{"type":"string"}},"warnings":{"type":"array","items":{"type":"string"}}}}}}},"403":{"description":"Missing security:debug permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/auth/register":{"post":{"summary":"Register a new user","tags":["Authentication"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email","password","name"],"properties":{"email":{"type":"string","format":"email"},"password":{"type":"string","minLength":8},"name":{"type":"string"}}}}}},"responses":{"201":{"description":"User registered successfully. Verification email sent."},"400":{"description":"Invalid request body or email already exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (5 requests per minute)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/auth/forgot-password":{"post":{"summary":"Request password reset","tags":["Authentication"],"security":[],"description":"Sends a password reset email if the email exists","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email"}}}}}},"responses":{"200":{"description":"If the email exists, a reset link has been sent"},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/auth/reset-password":{"post":{"summary":"Reset password with token","tags":["Authentication"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["token","password"],"properties":{"token":{"type":"string","description":"Password reset token from email"},"password":{"type":"string","minLength":8,"description":"New password"}}}}}},"responses":{"200":{"description":"Password reset successfully"},"400":{"description":"Invalid or expired token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/auth/verify-email":{"get":{"summary":"Verify email address","tags":["Authentication"],"security":[],"parameters":[{"in":"query","name":"token","required":true,"schema":{"type":"string"},"description":"Email verification token"}],"responses":{"200":{"description":"Email verified successfully"},"400":{"description":"Invalid or expired token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/workspace/{workspaceSlug}/api/v1/external-auth-providers":{"get":{"summary":"List external auth providers","tags":["External Auth Providers"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"query","name":"includeInactive","schema":{"type":"boolean"},"description":"Include inactive providers"}],"responses":{"200":{"description":"List of external auth providers","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/ExternalAuthProvider"}},"meta":{"type":"object","properties":{"total":{"type":"integer"}}}}}}}}}},"post":{"summary":"Create an external auth provider","tags":["External Auth Providers"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","slug","providerType","issuer"],"properties":{"name":{"type":"string"},"slug":{"type":"string"},"providerType":{"type":"string","enum":["oidc","clerk","auth0","keycloak","okta","custom"]},"issuer":{"type":"string","format":"uri"},"jwksUrl":{"type":"string","format":"uri"},"allowedAudiences":{"type":"array","items":{"type":"string"}},"clockSkewSeconds":{"type":"integer","default":60},"allowedAlgorithms":{"type":"array","items":{"type":"string"},"default":["RS256"]},"claimMappings":{"type":"array","items":{"$ref":"#/components/schemas/ClaimMapping"}},"allowedOrigins":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"201":{"description":"Provider created"},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Provider with this slug or issuer already exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/workspace/{workspaceSlug}/api/v1/external-auth-providers/{providerId}":{"get":{"summary":"Get an external auth provider","tags":["External Auth Providers"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"providerId","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Provider details"},"404":{"description":"Provider not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"summary":"Update an external auth provider","tags":["External Auth Providers"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"providerId","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"jwksUrl":{"type":"string","format":"uri"},"allowedAudiences":{"type":"array","items":{"type":"string"}},"clockSkewSeconds":{"type":"integer"},"allowedAlgorithms":{"type":"array","items":{"type":"string"}},"claimMappings":{"type":"array","items":{"$ref":"#/components/schemas/ClaimMapping"}},"allowedOrigins":{"type":"array","items":{"type":"string"}},"isActive":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Provider updated"},"404":{"description":"Provider not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"summary":"Delete an external auth provider","tags":["External Auth Providers"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"providerId","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Provider deleted"},"404":{"description":"Provider not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/workspace/{workspaceSlug}/api/v1/external-auth-providers/{providerId}/test-extraction":{"post":{"summary":"Test claim extraction with a sample JWT","description":"Decodes a JWT (without verification) and tests claim extraction\nusing the provider's configured mappings. Useful for developers\nto validate their claim mappings before deploying.\n","tags":["External Auth Providers"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"providerId","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["token"],"properties":{"token":{"type":"string","description":"JWT token to test"}}}}}},"responses":{"200":{"description":"Extraction test results","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"tokenPayload":{"type":"object"},"extractionResult":{"type":"object","properties":{"success":{"type":"boolean"},"attributes":{"type":"object"},"errors":{"type":"array","items":{"type":"string"}},"warnings":{"type":"array","items":{"type":"string"}}}}}}}}}}},"404":{"description":"Provider not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/workspace/{workspaceSlug}/api/v1/external-auth-providers/{providerId}/refresh-jwks":{"post":{"summary":"Refresh JWKS cache for a provider","description":"Forces a refresh of the cached JWKS from the provider.\nUseful after key rotation.\n","tags":["External Auth Providers"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"providerId","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"JWKS cache refreshed"},"404":{"description":"Provider not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/workspace/{workspaceSlug}/api/v1/oauth-clients":{"post":{"summary":"Register a new OAuth client","tags":["OAuth Clients"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","allowedScopes"],"properties":{"name":{"type":"string","description":"Display name for the OAuth client"},"description":{"type":"string","description":"Optional description"},"allowedScopes":{"type":"array","items":{"type":"string"},"description":"OAuth scopes this client can request (e.g., records:read, files:write)"}}}}}},"responses":{"201":{"description":"OAuth client created (client_secret shown only once)"},"400":{"description":"Invalid input"}}},"get":{"summary":"List all OAuth clients","tags":["OAuth Clients"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"query","name":"page","schema":{"type":"integer","default":1}},{"in":"query","name":"pageSize","schema":{"type":"integer","default":20}}],"responses":{"200":{"description":"List of OAuth clients"}}}},"/workspace/{workspaceSlug}/api/v1/oauth-clients/{id}":{"get":{"summary":"Get OAuth client details","tags":["OAuth Clients"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OAuth client details"},"404":{"description":"OAuth client not found"}}},"patch":{"summary":"Update an OAuth client","tags":["OAuth Clients"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"allowedScopes":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"200":{"description":"Updated OAuth client"},"409":{"description":"Client is revoked"}}},"delete":{"summary":"Revoke an OAuth client","tags":["OAuth Clients"],"description":"Revokes the client and all its active tokens","parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Client revoked"},"409":{"description":"Client already revoked"}}}},"/workspace/{workspaceSlug}/api/v1/oauth-clients/{id}/rotate":{"post":{"summary":"Rotate OAuth client secret","tags":["OAuth Clients"],"description":"Generates a new secret. The old secret is immediately invalidated.","parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"New secret generated (shown only once)"},"409":{"description":"Client is revoked"}}}},"/oauth/token":{"post":{"summary":"Request an access token","tags":["OAuth 2.0"],"description":"OAuth 2.0 Token Endpoint (RFC 6749 §3.2).\nSupports `client_credentials`, `authorization_code`, and `refresh_token` grant types.\n\nClient authentication can be provided via:\n- HTTP Basic auth header (preferred): `Authorization: Basic base64(client_id:client_secret)`\n- Request body: `client_id` and `client_secret` parameters\n","requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"type":"object","required":["grant_type"],"properties":{"grant_type":{"type":"string","enum":["client_credentials","authorization_code","refresh_token"],"description":"OAuth grant type"},"client_id":{"type":"string","description":"OAuth client ID"},"client_secret":{"type":"string","description":"OAuth client secret (required for confidential clients)"},"scope":{"type":"string","description":"Space-separated list of requested scopes"},"code":{"type":"string","description":"Authorization code (for authorization_code grant)"},"redirect_uri":{"type":"string","description":"Redirect URI used in authorization request (for authorization_code grant)"},"code_verifier":{"type":"string","description":"PKCE code verifier (for authorization_code grant with PKCE)"},"refresh_token":{"type":"string","description":"Refresh token (for refresh_token grant)"}}}}}},"responses":{"200":{"description":"Access token issued","content":{"application/json":{"schema":{"type":"object","properties":{"access_token":{"type":"string"},"token_type":{"type":"string","enum":["Bearer"]},"expires_in":{"type":"integer","description":"Token lifetime in seconds"},"scope":{"type":"string","description":"Granted scopes (space-separated)"},"refresh_token":{"type":"string","description":"Refresh token (for authorization_code and refresh_token grants)"}}}}}},"400":{"description":"Invalid request, unsupported grant type, invalid scope, or invalid grant"},"401":{"description":"Client authentication failed"}}}},"/oauth/authorize":{"get":{"summary":"Authorization endpoint (Authorization Code + PKCE)","tags":["OAuth 2.0"],"description":"OAuth 2.0 Authorization Endpoint (RFC 6749 §3.1).\nInitiates the Authorization Code flow. Redirects the user to login (if not authenticated)\nthen to a consent screen showing requested permissions. On approval, redirects back to\nthe client's redirect URI with an authorization code.\n\nFor public clients (no secret), PKCE is required (code_challenge + code_challenge_method=S256).\nFor loopback redirect URIs (localhost/127.0.0.1), any port is accepted per RFC 8252 §7.3.\n","parameters":[{"in":"query","name":"response_type","required":true,"schema":{"type":"string","enum":["code"]}},{"in":"query","name":"client_id","required":true,"schema":{"type":"string"}},{"in":"query","name":"redirect_uri","required":true,"schema":{"type":"string"}},{"in":"query","name":"scope","schema":{"type":"string"},"description":"Space-separated scopes (defaults to all client-allowed scopes)"},{"in":"query","name":"state","schema":{"type":"string"},"description":"Opaque CSRF state value (recommended)"},{"in":"query","name":"code_challenge","schema":{"type":"string"},"description":"PKCE code challenge (required for public clients)"},{"in":"query","name":"code_challenge_method","schema":{"type":"string","enum":["S256"]}}],"responses":{"302":{"description":"Redirects to login, consent, or callback with code"},"400":{"description":"Invalid client, redirect URI, or parameters"}}}},"/oauth/revoke":{"post":{"summary":"Revoke an access token","tags":["OAuth 2.0"],"description":"OAuth 2.0 Token Revocation (RFC 7009).\nAlways returns 200 per the spec, even for invalid tokens.\n","requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"type":"object","required":["token"],"properties":{"token":{"type":"string","description":"The access token to revoke"},"client_id":{"type":"string"},"client_secret":{"type":"string"}}}},"application/json":{"schema":{"type":"object","required":["token"],"properties":{"token":{"type":"string"},"client_id":{"type":"string"},"client_secret":{"type":"string"}}}}}},"responses":{"200":{"description":"Token revoked (always returns 200 per RFC 7009)"},"401":{"description":"Client authentication failed"}}}},"/workspace/{workspaceSlug}/api/v1/publishable-keys":{"post":{"summary":"Create a new publishable key","tags":["Publishable Keys"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["label","scopes"],"properties":{"label":{"type":"string","description":"User-provided name for the key"},"scopes":{"type":"array","items":{"type":"string"},"description":"Array of resource:action:target scope strings"}}}}}},"responses":{"201":{"description":"Key created (full key returned only this once)"},"400":{"description":"Invalid input"}}},"get":{"summary":"List all publishable keys","tags":["Publishable Keys"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"query","name":"page","schema":{"type":"integer","default":1}},{"in":"query","name":"pageSize","schema":{"type":"integer","default":20}}],"responses":{"200":{"description":"List of publishable keys (masked)"}}}},"/workspace/{workspaceSlug}/api/v1/publishable-keys/{id}":{"get":{"summary":"Get publishable key details","tags":["Publishable Keys"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Key details (masked)"},"404":{"description":"Key not found"}}},"patch":{"summary":"Update a publishable key's label or scopes","tags":["Publishable Keys"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"200":{"description":"Updated key"},"409":{"description":"Key is revoked"}}},"delete":{"summary":"Revoke a publishable key","tags":["Publishable Keys"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Key revoked"},"409":{"description":"Key already revoked"}}}},"/workspace/{workspaceSlug}/api/v1/service-accounts":{"get":{"summary":"List all service accounts","tags":["Service Accounts"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of service accounts","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/ServiceAccount"}}}}}}}}},"post":{"summary":"Create a new service account","tags":["Service Accounts"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","description":"Display name for the service account"},"description":{"type":"string","description":"Optional description"}}}}}},"responses":{"201":{"description":"Service account created. Returns client_id and client_secret (secret shown only once)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"client_id":{"type":"string"},"client_secret":{"type":"string","description":"Only returned on creation"}}}}}}}}}}},"/workspace/{workspaceSlug}/api/v1/service-accounts/{cid}":{"get":{"summary":"Get a specific service account","tags":["Service Accounts"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"cid","required":true,"schema":{"type":"string"},"description":"Client ID"}],"responses":{"200":{"description":"Service account details"},"404":{"description":"Service account not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"summary":"Delete a service account","tags":["Service Accounts"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"cid","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Service account deleted"}}}},"/workspace/{workspaceSlug}/api/v1/service-accounts/{cid}/name":{"put":{"summary":"Update service account name","tags":["Service Accounts"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"cid","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string"}}}}}},"responses":{"200":{"description":"Name updated successfully"}}}},"/workspace/{workspaceSlug}/api/v1/service-accounts/{cid}/description":{"put":{"summary":"Update service account description","tags":["Service Accounts"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"cid","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"description":{"type":"string"}}}}}},"responses":{"200":{"description":"Description updated successfully"}}}},"/workspace/{workspaceSlug}/api/v1/service-accounts/{cid}/revoke":{"post":{"summary":"Revoke a service account","tags":["Service Accounts"],"description":"Invalidates all tokens for this service account","parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"cid","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Service account revoked"}}}},"/workspace/{workspaceSlug}/api/v1/service-accounts/{cid}/rotate":{"post":{"summary":"Rotate client secret","tags":["Service Accounts"],"description":"Generates a new client secret. The old secret is immediately invalidated.","parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"cid","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"New client secret generated","content":{"application/json":{"schema":{"type":"object","properties":{"client_secret":{"type":"string","description":"New client secret (shown only once)"}}}}}}}}},"/workspace/{workspaceSlug}/api/v1/service-accounts/{serviceAccountId}/permissions/scan":{"get":{"summary":"Scan all permissions for a service account","tags":["Permission Introspection"],"description":"Returns a complete access matrix showing all allowed and denied actions\nfor the specified service account across all resources.\n\nRequires `security:debug` permission on `workspace::service-accounts`.\n","parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"serviceAccountId","required":true,"schema":{"type":"integer"},"description":"Numeric ID of the service account (oidc_clients.id)"},{"in":"query","name":"filter","schema":{"type":"string","enum":["all","allowed","denied"],"default":"all"},"description":"Filter results by decision"},{"in":"query","name":"resourceCategory","schema":{"type":"string"},"description":"Filter by resource category (e.g., \"workspace\", \"billing\")"}],"responses":{"200":{"description":"Permission scan results","content":{"application/json":{"schema":{"type":"object","properties":{"serviceAccount":{"type":"object","properties":{"id":{"type":"integer"},"clientId":{"type":"string"},"name":{"type":"string"},"groups":{"type":"array","items":{"type":"string"}},"roles":{"type":"array","items":{"type":"string"}}}},"accessMatrix":{"type":"array","items":{"type":"object","properties":{"resource":{"type":"object","properties":{"name":{"type":"string"},"category":{"type":"string"}}},"permissions":{"type":"array","items":{"type":"object","properties":{"action":{"type":"string"},"decision":{"type":"string","enum":["Allow","Deny"]},"reason":{"type":"string"},"requiredConditions":{"type":"array","items":{"type":"string"}}}}}}}},"summary":{"type":"object","properties":{"totalResources":{"type":"integer"},"totalActions":{"type":"integer"},"allowedActions":{"type":"integer"},"deniedActions":{"type":"integer"}}}}}}}},"403":{"description":"Missing security:debug permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Service account not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/workspace/{workspaceSlug}/api/v1/service-accounts/{serviceAccountId}/permissions/simulate":{"post":{"summary":"Simulate an authorization check with detailed trace","tags":["Permission Introspection"],"description":"Performs a detailed simulation of an authorization check, returning\nstep-by-step evaluation trace and suggestions for granting access.\n\nRequires `security:debug` permission on `workspace::service-accounts`.\n","parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"serviceAccountId","required":true,"schema":{"type":"integer"},"description":"Numeric ID of the service account (oidc_clients.id)"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["resource","resourceCategory","action"],"properties":{"resource":{"type":"string","description":"Resource name to evaluate (e.g., \"workspace::users\")"},"resourceCategory":{"type":"string","description":"Resource category (e.g., \"workspace\")"},"action":{"type":"string","description":"Action to evaluate (e.g., \"delete\")"},"context":{"type":"object","description":"Optional context overrides for simulation","properties":{"ipAddress":{"type":"string"},"timeOverride":{"type":"string"},"requestMetadata":{"type":"object"}}}}}}}},"responses":{"200":{"description":"Simulation results with trace","content":{"application/json":{"schema":{"type":"object","properties":{"decision":{"type":"string","enum":["Allow","Deny"]},"evaluationContext":{"type":"object","description":"All variables used in evaluation"},"evaluationTrace":{"type":"array","description":"Step-by-step evaluation trace","items":{"type":"object","properties":{"step":{"type":"integer"},"type":{"type":"string"},"description":{"type":"string"},"result":{"type":"string"}}}},"suggestion":{"type":"object","description":"Suggestions for granting access (when denied)","properties":{"toGrantAccess":{"type":"array","items":{"type":"string"}}}},"serviceAccount":{"type":"object"}}}}}},"403":{"description":"Missing security:debug permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Service account not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/workspace/{workspaceSlug}/api/v1/frontend-clients":{"get":{"summary":"List all frontend clients","tags":["Frontend Clients"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of frontend clients"}}},"post":{"summary":"Create a new frontend client","tags":["Frontend Clients"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","redirect_uris"],"properties":{"name":{"type":"string"},"description":{"type":"string"},"redirect_uris":{"type":"array","items":{"type":"string","format":"uri"},"description":"Allowed OAuth redirect URIs"}}}}}},"responses":{"201":{"description":"Frontend client created"}}}},"/workspace/{workspaceSlug}/api/v1/frontend-clients/{cid}":{"get":{"summary":"Get a specific frontend client","tags":["Frontend Clients"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"cid","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Frontend client details"}}},"delete":{"summary":"Delete a frontend client","tags":["Frontend Clients"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"cid","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Frontend client deleted"}}}},"/workspace/{workspaceSlug}/api/v1/frontend-clients/{cid}/redirect-uris":{"put":{"summary":"Update redirect URIs","tags":["Frontend Clients"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"cid","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["redirect_uris"],"properties":{"redirect_uris":{"type":"array","items":{"type":"string","format":"uri"}}}}}}},"responses":{"200":{"description":"Redirect URIs updated"}}}},"/workspace/{workspaceSlug}/api/v1/frontend-clients/{cid}/name":{"put":{"summary":"Update frontend client name","tags":["Frontend Clients"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"cid","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string"}}}}}},"responses":{"200":{"description":"Name updated"}}}},"/workspace/{workspaceSlug}/api/v1/frontend-clients/{cid}/description":{"put":{"summary":"Update frontend client description","tags":["Frontend Clients"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"cid","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"description":{"type":"string"}}}}}},"responses":{"200":{"description":"Description updated"}}}},"/workspace/{workspaceSlug}/api/v1/frontend-clients/{cid}/revoke":{"post":{"summary":"Revoke a frontend client","tags":["Frontend Clients"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"cid","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Client revoked"}}}},"/workspace/{workspaceSlug}/api/v1/frontend-clients/{cid}/rotate":{"post":{"summary":"Rotate client secret","tags":["Frontend Clients"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"cid","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"New client secret generated"}}}},"/workspace/{workspaceSlug}/api/v1/users":{"get":{"summary":"List all users","tags":["Users"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"query","name":"page","schema":{"type":"integer","default":1}},{"in":"query","name":"limit","schema":{"type":"integer","default":20}},{"in":"query","name":"search","schema":{"type":"string"},"description":"Search by name or email"}],"responses":{"200":{"description":"List of users","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/User"}}}}}}}}},"post":{"summary":"Create a new user","tags":["Users"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email","name"],"properties":{"email":{"type":"string","format":"email"},"name":{"type":"string"},"password":{"type":"string","description":"If not provided, user will receive an invitation email"}}}}}},"responses":{"201":{"description":"User created successfully"}}}},"/workspace/{workspaceSlug}/api/v1/users/{id}":{"get":{"summary":"Get a specific user","tags":["Users"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"User details"},"404":{"description":"User not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"summary":"Update a user","tags":["Users"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"email":{"type":"string","format":"email"}}}}}},"responses":{"200":{"description":"User updated successfully"}}},"delete":{"summary":"Delete a user","tags":["Users"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"User deleted successfully"}}}},"/workspace/{workspaceSlug}/api/v1/users/{id}/avatar":{"post":{"summary":"Upload user avatar","tags":["Users"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"avatar":{"type":"string","format":"binary"}}}}}},"responses":{"200":{"description":"Avatar uploaded successfully","content":{"application/json":{"schema":{"type":"object","properties":{"avatar_url":{"type":"string","format":"uri"}}}}}}}}},"/workspace/{workspaceSlug}/api/v1/users/{id}/attributes":{"get":{"summary":"List user attributes","tags":["Users"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"List of user attributes"}}},"post":{"summary":"Create or update a user attribute","tags":["Users"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["key","value"],"properties":{"key":{"type":"string"},"value":{"type":"string"}}}}}},"responses":{"200":{"description":"Attribute upserted successfully"}}}},"/workspace/{workspaceSlug}/api/v1/users/{id}/attributes/{key}":{"delete":{"summary":"Delete a user attribute","tags":["Users"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"path","name":"key","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Attribute deleted"}}}},"/workspace/{workspaceSlug}/api/v1/users/{id}/change-password":{"post":{"summary":"Change user password (authenticated)","tags":["Users"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["newPassword"],"properties":{"currentPassword":{"type":"string","description":"Current password (required if user is changing their own password)"},"newPassword":{"type":"string","minLength":8}}}}}},"responses":{"200":{"description":"Password changed successfully"}}}},"/workspace/{workspaceSlug}/api/v1/users/{id}/roles":{"get":{"summary":"Get roles assigned to a user","tags":["Users"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"List of roles"}}}},"/workspace/{workspaceSlug}/api/v1/users/{id}/roles/{roleId}":{"post":{"summary":"Assign a role to a user","tags":["Users"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"path","name":"roleId","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Role assigned successfully"}}},"delete":{"summary":"Remove a role from a user","tags":["Users"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"path","name":"roleId","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Role removed successfully"}}}},"/workspace/{workspaceSlug}/api/v1/users/{id}/groups":{"get":{"summary":"Get groups a user belongs to","tags":["Users"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"List of groups"}}}},"/workspace/{workspaceSlug}/api/v1/users/{id}/groups/{groupId}":{"post":{"summary":"Add a user to a group","tags":["Users"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"path","name":"groupId","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"User added to group"}}},"delete":{"summary":"Remove a user from a group","tags":["Users"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"path","name":"groupId","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"User removed from group"}}}},"/workspace/{workspaceSlug}/api/v1/preferences":{"get":{"summary":"Get current user's console preferences","tags":["User Preferences"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"User preferences blob","content":{"application/json":{"schema":{"type":"object","properties":{"preferences":{"type":"object","description":"All user preferences as a single JSON object"}}}}}}}},"put":{"summary":"Replace all console preferences","tags":["User Preferences"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"Full preferences object to replace existing preferences"}}}},"responses":{"204":{"description":"Preferences replaced"}}},"patch":{"summary":"Merge partial updates into console preferences","tags":["User Preferences"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"Partial preferences to merge with existing preferences"}}}},"responses":{"200":{"description":"Merged preferences","content":{"application/json":{"schema":{"type":"object","properties":{"preferences":{"type":"object","description":"The resulting merged preferences object"}}}}}}}}},"/workspace/{workspaceSlug}/api/v1/roles":{"get":{"summary":"List all roles","tags":["Roles"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of roles","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Role"}}}}}}}}},"post":{"summary":"Create a new role","tags":["Roles"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"description":{"type":"string"},"permissions":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Array of permission IDs to assign"}}}}}},"responses":{"201":{"description":"Role created successfully"}}}},"/workspace/{workspaceSlug}/api/v1/roles/{id}":{"get":{"summary":"Get a specific role","tags":["Roles"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Role details"}}},"put":{"summary":"Update a role","tags":["Roles"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"permissions":{"type":"array","items":{"type":"string","format":"uuid"}}}}}}},"responses":{"200":{"description":"Role updated successfully"}}},"delete":{"summary":"Delete a role","tags":["Roles"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Role deleted successfully"}}}},"/workspace/{workspaceSlug}/api/v1/roles/{id}/users":{"get":{"summary":"List users with this role","tags":["Roles"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"List of users"}}}},"/workspace/{workspaceSlug}/api/v1/roles/{id}/service-accounts":{"get":{"summary":"List service accounts with this role","tags":["Roles"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"List of service accounts"}}}},"/workspace/{workspaceSlug}/api/v1/groups":{"get":{"summary":"List all groups","tags":["Groups"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of groups"}}},"post":{"summary":"Create a new group","tags":["Groups"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"description":{"type":"string"}}}}}},"responses":{"201":{"description":"Group created successfully"}}}},"/workspace/{workspaceSlug}/api/v1/groups/{id}":{"get":{"summary":"Get a specific group","tags":["Groups"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Group details"}}},"put":{"summary":"Update a group","tags":["Groups"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"}}}}}},"responses":{"200":{"description":"Group updated successfully"}}},"delete":{"summary":"Delete a group","tags":["Groups"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Group deleted successfully"}}}},"/workspace/{workspaceSlug}/api/v1/groups/{id}/users":{"get":{"summary":"List users in this group","tags":["Groups"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"List of users"}}}},"/workspace/{workspaceSlug}/api/v1/groups/{id}/service-accounts":{"get":{"summary":"List service accounts in this group","tags":["Groups"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"List of service accounts"}}}},"/workspace/{workspaceSlug}/api/v1/service-accounts/{id}/groups":{"get":{"summary":"Get groups a service account belongs to","tags":["Service Accounts"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of groups"}}}},"/workspace/{workspaceSlug}/api/v1/service-accounts/{id}/groups/{groupId}":{"post":{"summary":"Add service account to a group","tags":["Service Accounts"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"in":"path","name":"groupId","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Service account added to group"}}},"delete":{"summary":"Remove service account from a group","tags":["Service Accounts"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"in":"path","name":"groupId","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Service account removed from group"}}}},"/workspace/{workspaceSlug}/api/v1/service-accounts/{id}/roles":{"get":{"summary":"Get roles assigned to a service account","tags":["Service Accounts"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of roles"}}}},"/workspace/{workspaceSlug}/api/v1/service-accounts/{id}/roles/{roleId}":{"post":{"summary":"Assign a role to a service account","tags":["Service Accounts"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"in":"path","name":"roleId","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Role assigned successfully"}}},"delete":{"summary":"Remove a role from a service account","tags":["Service Accounts"],"parameters":[{"in":"path","name":"workspaceSlug","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"in":"path","name":"roleId","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Role removed successfully"}}}},"/api/v1/my-workspaces":{"get":{"summary":"Get current user's workspaces","tags":["Workspace Selection"],"description":"Returns all workspaces the authenticated user has access to","responses":{"200":{"description":"List of workspaces","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"},"role":{"type":"string","description":"User's role in this workspace"}}}}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/switch-workspace":{"post":{"summary":"Switch to a different workspace","tags":["Workspace Selection"],"description":"Updates the user's current workspace context and returns new tokens","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["workspaceSlug"],"properties":{"workspaceSlug":{"type":"string","description":"Slug of the workspace to switch to"}}}}}},"responses":{"200":{"description":"Successfully switched workspace","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"workspace":{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"}}}}}}}}}},"403":{"description":"User does not have access to this workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Workspace not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"tags":[{"name":"Allowed User Attributes","description":"Manage allowed user attributes for access control"},{"name":"Resources","description":"Manage protected resources"},{"name":"Permissions","description":"Manage access permissions"},{"name":"Policies","description":"Manage access control policies"},{"name":"Access Evaluation","description":"Evaluate access decisions"},{"name":"Functions","description":"List available policy functions"},{"name":"Allowed Attributes","description":"List allowed policy attributes"},{"name":"Generative Operations","description":"AI-powered policy operations"},{"name":"Authentication","description":"User registration and password management"},{"name":"External Auth Providers","description":"Manage external identity providers for BYOT (Bring Your Own Token)"},{"name":"OAuth Clients","description":"Manage OAuth 2.0 client applications"},{"name":"OAuth 2.0","description":"OAuth 2.0 token endpoints (RFC 6749)"},{"name":"Publishable Keys","description":"Manage scoped publishable keys for frontend API access"},{"name":"Service Accounts","description":"Manage service accounts for API access"},{"name":"Frontend Clients","description":"Manage frontend OAuth clients"},{"name":"Permission Introspection","description":"Debug and troubleshoot service account permissions"},{"name":"Users","description":"User management"},{"name":"Roles","description":"Role management"},{"name":"Groups","description":"Group management"},{"name":"User Preferences","description":"User preference settings"},{"name":"Workspace Selection","description":"Get user's workspaces and switch between them"}]}