{
  "openapi": "3.0.0",
  "info": {
    "version": "2.0.0",
    "title": "Merrows Auth API",
    "description": "Authentication and business management API with unified MFA support"
  },
  "tags": [
    {
      "name": "Authentication",
      "description": "User authentication and session management"
    },
    {
      "name": "MFA",
      "description": "Multi-factor authentication operations"
    },
    {
      "name": "Tenants",
      "description": "Tenant management operations"
    },
    {
      "name": "Roles",
      "description": "Role and permission management"
    },
    {
      "name": "Permissions",
      "description": "Permission-based access control operations"
    }
  ],
  "paths": {
    "/auth/register": {
      "post": {
        "tags": [
          "Authentication"
        ],
        "summary": "Register new user",
        "description": "Create a new user account with email or phone number",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RegisterRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Registration successful",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/auth/login": {
      "post": {
        "tags": [
          "Authentication"
        ],
        "summary": "User login",
        "description": "Authenticate user with email/phone and password",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LoginRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Login successful",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid credentials",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "MFA challenge store unavailable (error.code MFA_STORE_UNAVAILABLE). The account is MFA-enrolled and the service's Redis client is not ready; no code was sent. Retry after the Retry-After header (seconds).",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/auth/verify": {
      "post": {
        "tags": [
          "Authentication"
        ],
        "summary": "Verify email or phone",
        "description": "Verify user's email or phone number with code",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VerifyRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Verification successful",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid or expired code",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/auth/resend-verification": {
      "post": {
        "tags": [
          "Authentication"
        ],
        "summary": "Resend verification code",
        "description": "Resend verification code to email or phone",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "userId",
                  "method"
                ],
                "properties": {
                  "userId": {
                    "type": "integer"
                  },
                  "method": {
                    "type": "string",
                    "enum": [
                      "email",
                      "sms"
                    ]
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Code sent successfully",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          }
        }
      }
    },
    "/auth/forgot-password": {
      "post": {
        "tags": [
          "Authentication"
        ],
        "summary": "Request password reset",
        "description": "Send password reset code to user's email or phone",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "identifier"
                ],
                "properties": {
                  "identifier": {
                    "type": "string",
                    "description": "Email or phone number"
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Reset code sent",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          }
        }
      }
    },
    "/auth/reset-password": {
      "post": {
        "tags": [
          "Authentication"
        ],
        "summary": "Reset password",
        "description": "Reset password using verification code",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ResetPasswordRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Password reset successful",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          }
        }
      }
    },
    "/auth/setup-mfa": {
      "post": {
        "tags": [
          "MFA"
        ],
        "summary": "Start MFA enrolment (step one of two)",
        "description": "Begins enrolling a second factor on the authenticated user's own account (#2500). Nothing is enabled by this call. For `authenticator` a TOTP secret is stored and returned with its otpauth URI; for `email` or `sms` a code is sent to the verified contact. Call POST /auth/confirm-mfa with a code from the method to enable it. The user is taken from the JWT; a body-supplied userId is ignored.",
        "security": [
          {
            "Bearer": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "methods"
                ],
                "properties": {
                  "methods": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "email",
                        "sms",
                        "authenticator"
                      ]
                    }
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Enrolment started. data carries mfa_enabled and mfa_methods (both unchanged), pending_methods, totp { secret, otpauthUri } when authenticator was requested, and delivery [{ method, delivered, expiresAt }] for email/sms.",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          },
          "400": {
            "description": "A requested method is already enabled on the account, its contact is not verified, or the code could not be sent.",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/auth/confirm-mfa": {
      "post": {
        "tags": [
          "MFA"
        ],
        "summary": "Confirm MFA enrolment (step two of two)",
        "description": "Enables the pending method on the authenticated user's own account once the submitted code checks out: a TOTP from the secret returned by /auth/setup-mfa, or the code it sent by email or SMS. A wrong code answers 400 MFA_CONFIRM_FAILED and changes nothing. Rate limited to 5 attempts per 15 minutes per user and 30 per hour per IP.",
        "security": [
          {
            "Bearer": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "method",
                  "code"
                ],
                "properties": {
                  "method": {
                    "type": "string",
                    "enum": [
                      "email",
                      "sms",
                      "authenticator"
                    ]
                  },
                  "code": {
                    "type": "string",
                    "description": "Six-digit code from the method being enrolled"
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "MFA enabled. data carries mfa_enabled (true) and mfa_methods.",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          },
          "400": {
            "description": "The code did not check out (error.code MFA_CONFIRM_FAILED), or no enrolment is pending for the method.",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated"
          },
          "429": {
            "description": "Too many attempts; see Retry-After"
          }
        }
      }
    },
    "/auth/disable-mfa": {
      "post": {
        "tags": [
          "MFA"
        ],
        "summary": "Disable MFA",
        "description": "Disable multi-factor authentication for user",
        "security": [
          {
            "Bearer": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "userId"
                ],
                "properties": {
                  "userId": {
                    "type": "integer"
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "MFA disabled",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          }
        }
      }
    },
    "/auth/verify-mfa": {
      "post": {
        "tags": [
          "MFA"
        ],
        "summary": "Verify MFA challenge",
        "description": "Verify multi-factor authentication codes",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MFAVerifyRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "MFA verified successfully",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "503": {
            "description": "MFA challenge store unavailable (error.code MFA_STORE_UNAVAILABLE). The service's Redis client is not ready, so the challenge could not be consumed; the challenge is still valid. Retry after the Retry-After header (seconds).",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/auth/logout": {
      "post": {
        "tags": [
          "Authentication"
        ],
        "summary": "Logout user",
        "description": "Invalidate user session and token",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "sessionId": {
                    "type": "string"
                  },
                  "userId": {
                    "type": "integer"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Logout successful",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          }
        }
      }
    },
    "/auth/verify-token": {
      "get": {
        "tags": [
          "Authentication"
        ],
        "summary": "Verify JWT token",
        "description": "Check if JWT token is valid",
        "security": [
          {
            "Bearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "Token is valid",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/TokenVerifyResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid token",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/auth/google": {
      "get": {
        "tags": [
          "Authentication"
        ],
        "summary": "Google OAuth",
        "description": "Initiate Google OAuth authentication",
        "responses": {
          "302": {
            "description": "Redirect to Google"
          }
        }
      }
    },
    "/auth/google/callback": {
      "get": {
        "tags": [
          "Authentication"
        ],
        "summary": "Google OAuth Callback",
        "description": "Handle Google OAuth callback",
        "parameters": [
          {
            "in": "query",
            "name": "code",
            "description": "Authorization code from Google",
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "state",
            "description": "State parameter",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "302": {
            "description": "Redirect after authentication"
          },
          "400": {
            "description": "Authentication failed",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/auth/apple": {
      "get": {
        "tags": [
          "Authentication"
        ],
        "summary": "Apple OAuth",
        "description": "Initiate Apple OAuth authentication",
        "responses": {
          "302": {
            "description": "Redirect to Apple"
          }
        }
      }
    },
    "/auth/apple/callback": {
      "get": {
        "tags": [
          "Authentication"
        ],
        "summary": "Apple OAuth Callback",
        "description": "Handle Apple OAuth callback",
        "parameters": [
          {
            "in": "query",
            "name": "code",
            "description": "Authorization code from Apple",
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "state",
            "description": "State parameter",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "302": {
            "description": "Redirect after authentication"
          },
          "400": {
            "description": "Authentication failed",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/auth/facebook": {
      "get": {
        "tags": [
          "Authentication"
        ],
        "summary": "Facebook OAuth",
        "description": "Initiate Facebook OAuth authentication",
        "responses": {
          "302": {
            "description": "Redirect to Facebook"
          }
        }
      }
    },
    "/auth/facebook/callback": {
      "get": {
        "tags": [
          "Authentication"
        ],
        "summary": "Facebook OAuth Callback",
        "description": "Handle Facebook OAuth callback",
        "parameters": [
          {
            "in": "query",
            "name": "code",
            "description": "Authorization code from Facebook",
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "state",
            "description": "State parameter",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "302": {
            "description": "Redirect after authentication"
          },
          "400": {
            "description": "Authentication failed",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/auth/microsoft": {
      "get": {
        "tags": [
          "Authentication"
        ],
        "summary": "Microsoft OAuth",
        "description": "Initiate Microsoft OAuth authentication",
        "responses": {
          "302": {
            "description": "Redirect to Microsoft"
          }
        }
      }
    },
    "/auth/microsoft/callback": {
      "get": {
        "tags": [
          "Authentication"
        ],
        "summary": "Microsoft OAuth Callback",
        "description": "Handle Microsoft OAuth callback",
        "parameters": [
          {
            "in": "query",
            "name": "code",
            "description": "Authorization code from Microsoft",
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "state",
            "description": "State parameter",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "302": {
            "description": "Redirect after authentication"
          },
          "400": {
            "description": "Authentication failed",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/auth/tiktok": {
      "get": {
        "tags": [
          "Authentication"
        ],
        "summary": "TikTok OAuth",
        "description": "Initiate TikTok OAuth authentication",
        "responses": {
          "302": {
            "description": "Redirect to TikTok"
          }
        }
      }
    },
    "/auth/tiktok/callback": {
      "get": {
        "tags": [
          "Authentication"
        ],
        "summary": "TikTok OAuth Callback",
        "description": "Handle TikTok OAuth callback",
        "parameters": [
          {
            "in": "query",
            "name": "code",
            "description": "Authorization code from TikTok",
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "state",
            "description": "State parameter",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "302": {
            "description": "Redirect after authentication"
          },
          "400": {
            "description": "Authentication failed",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/tenants/{slug}": {
      "get": {
        "tags": [
          "Tenants"
        ],
        "summary": "Get business",
        "description": "Get business details by slug",
        "security": [
          {
            "Bearer": []
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "slug",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Business details",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/BusinessResponse"
                }
              }
            }
          },
          "404": {
            "description": "Business not found",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/tenants/{slug}/users": {
      "get": {
        "tags": [
          "Tenants"
        ],
        "summary": "Get business users",
        "description": "List all users in a business",
        "security": [
          {
            "Bearer": []
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "slug",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "User list",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/BusinessUsersResponse"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Tenants"
        ],
        "summary": "Add user to business",
        "description": "Add a user to the business",
        "security": [
          {
            "Bearer": []
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "slug",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email",
                  "roleId"
                ],
                "properties": {
                  "email": {
                    "type": "string"
                  },
                  "roleId": {
                    "type": "integer"
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "User added",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          }
        }
      }
    },
    "/tenants/{slug}/users/{userIdentifier}": {
      "delete": {
        "tags": [
          "Tenants"
        ],
        "summary": "Remove user from business",
        "description": "Remove a user from the business",
        "security": [
          {
            "Bearer": []
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "slug",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "userIdentifier",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "User removed",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          }
        }
      }
    },
    "/tenants/{slug}/users/{userIdentifier}/role": {
      "put": {
        "tags": [
          "Tenants"
        ],
        "summary": "Update user role",
        "description": "Update user's role in business",
        "security": [
          {
            "Bearer": []
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "slug",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "userIdentifier",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "roleId"
                ],
                "properties": {
                  "roleId": {
                    "type": "integer"
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Role updated",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          }
        }
      }
    },
    "/tenants/{slug}/roles": {
      "get": {
        "tags": [
          "Tenants"
        ],
        "summary": "Get business roles",
        "description": "List all roles in a business",
        "security": [
          {
            "Bearer": []
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "slug",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Role list",
            "content": {
              "*/*": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "roles": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Role"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Tenants"
        ],
        "summary": "Create business role",
        "description": "Create a custom role for the business",
        "security": [
          {
            "Bearer": []
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "slug",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name",
                  "description"
                ],
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "description": {
                    "type": "string"
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Role created",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/Role"
                }
              }
            }
          }
        }
      }
    },
    "/tenants/my-tenants": {
      "get": {
        "tags": [
          "Tenants"
        ],
        "summary": "Get my businesses",
        "description": "List all businesses for authenticated user",
        "security": [
          {
            "Bearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "Business list",
            "content": {
              "*/*": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "businesses": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Business"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/roles": {
      "get": {
        "tags": [
          "Roles"
        ],
        "summary": "List roles",
        "description": "Get all available roles",
        "security": [
          {
            "Bearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "Role list",
            "content": {
              "*/*": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Role"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/permissions/{businessId}": {
      "get": {
        "tags": [
          "Permissions"
        ],
        "summary": "Get user permissions for business",
        "description": "Get user's permissions for a specific business",
        "security": [
          {
            "Bearer": []
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "businessId",
            "required": true,
            "description": "Business ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "User permissions",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/PermissionsResponse"
                }
              }
            }
          },
          "403": {
            "description": "Access denied",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Business not found",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/permissions/check": {
      "post": {
        "tags": [
          "Permissions"
        ],
        "summary": "Check user permission",
        "description": "Check if user has a specific permission in a business",
        "security": [
          {
            "Bearer": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "businessId",
                  "permissionName"
                ],
                "properties": {
                  "businessId": {
                    "type": "integer"
                  },
                  "permissionName": {
                    "type": "string"
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Permission check result",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/PermissionCheckResponse"
                }
              }
            }
          },
          "400": {
            "description": "Missing required parameters",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/permissions/available/all": {
      "get": {
        "tags": [
          "Permissions"
        ],
        "summary": "Get all available permissions",
        "description": "Get all permissions available in the system",
        "security": [
          {
            "Bearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "Available permissions",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/AvailablePermissionsResponse"
                }
              }
            }
          }
        }
      }
    },
    "/permissions/set-active-tenant": {
      "post": {
        "tags": [
          "Permissions"
        ],
        "summary": "Set active business",
        "description": "Set user's active business context",
        "security": [
          {
            "Bearer": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "businessId"
                ],
                "properties": {
                  "businessId": {
                    "type": "integer"
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Active business updated",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ActiveBusinessResponse"
                }
              }
            }
          },
          "403": {
            "description": "Access denied",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Business not found",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/decode": {
      "post": {
        "tags": [
          "Utilities"
        ],
        "summary": "Decode JWT",
        "description": "Decode and verify JWT token",
        "requestBody": {
          "$ref": "#/components/requestBodies/Body"
        },
        "responses": {
          "200": {
            "description": "Decoded token",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          }
        }
      }
    },
    "/tenants/{slug}/invitations": {
      "post": {
        "tags": [
          "Tenants"
        ],
        "summary": "Invite a member by email",
        "description": "Create a pending invitation and email an accept link. The invitee needs no account yet; accepting requires signing in with the invited address. Requires auth.users.manage (or global admin); owner roles require an owner actor.",
        "security": [
          {
            "Bearer": []
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "slug",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email",
                  "tenantRoleId"
                ],
                "properties": {
                  "email": {
                    "type": "string"
                  },
                  "tenantRoleId": {
                    "type": "integer"
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Invitation created (emailSent flags delivery)",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          },
          "409": {
            "description": "ALREADY_MEMBER or DUPLICATE_INVITE"
          }
        }
      },
      "get": {
        "tags": [
          "Tenants"
        ],
        "summary": "List member invitations",
        "description": "All invitations for the tenant, newest first; pending rows past expiry carry expired=true.",
        "security": [
          {
            "Bearer": []
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "slug",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Invitation list",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          }
        }
      }
    },
    "/tenants/{slug}/invitations/{id}/resend": {
      "post": {
        "tags": [
          "Tenants"
        ],
        "summary": "Resend a pending invitation",
        "description": "Rotates the token, extends the expiry, and emails a fresh accept link. The previously emailed link stops working.",
        "security": [
          {
            "Bearer": []
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "slug",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Invitation resent",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          }
        }
      }
    },
    "/tenants/{slug}/invitations/{id}": {
      "delete": {
        "tags": [
          "Tenants"
        ],
        "summary": "Revoke a pending invitation",
        "description": "Soft-revokes a pending invitation. Owner-role invitations require an owner actor.",
        "security": [
          {
            "Bearer": []
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "slug",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Invitation revoked",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          }
        }
      }
    },
    "/invitations/verify": {
      "get": {
        "tags": [
          "Invitations"
        ],
        "summary": "Verify an invitation token",
        "description": "Public. Returns tenant, role, inviter, and invited email for a pending, unexpired token; anything else is a uniform 404.",
        "parameters": [
          {
            "in": "query",
            "name": "token",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Invitation context",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          },
          "404": {
            "description": "INVALID_INVITE"
          }
        }
      }
    },
    "/invitations/accept": {
      "post": {
        "tags": [
          "Invitations"
        ],
        "summary": "Accept an invitation",
        "description": "Authenticated. The session email must match the invited address (case-insensitive). Creates the membership with the invited role; a user already holding a role accepts without gaining a second one.",
        "security": [
          {
            "Bearer": []
          }
        ],
        "requestBody": {
          "$ref": "#/components/requestBodies/Body"
        },
        "responses": {
          "200": {
            "description": "Membership created",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          },
          "403": {
            "description": "EMAIL_MISMATCH"
          },
          "409": {
            "description": "INVITE_ROLE_REMOVED"
          }
        }
      }
    }
  },
  "servers": [
    {
      "url": "https://auth.merrows.ai/api/v1",
      "description": "Production"
    }
  ],
  "components": {
    "requestBodies": {
      "Body": {
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "required": [
                "token"
              ],
              "properties": {
                "token": {
                  "type": "string"
                }
              }
            }
          }
        },
        "required": true
      }
    },
    "securitySchemes": {
      "Bearer": {
        "type": "apiKey",
        "name": "Authorization",
        "in": "header",
        "description": "Enter JWT token with Bearer prefix"
      }
    },
    "schemas": {
      "RegisterRequest": {
        "type": "object",
        "required": [
          "password",
          "firstName",
          "lastName"
        ],
        "properties": {
          "email": {
            "type": "string",
            "format": "email"
          },
          "phoneNumber": {
            "type": "string"
          },
          "password": {
            "type": "string",
            "minLength": 8
          },
          "firstName": {
            "type": "string"
          },
          "lastName": {
            "type": "string"
          },
          "username": {
            "type": "string"
          }
        }
      },
      "LoginRequest": {
        "type": "object",
        "required": [
          "identifier",
          "password"
        ],
        "properties": {
          "identifier": {
            "type": "string",
            "description": "Email or phone number"
          },
          "password": {
            "type": "string"
          }
        }
      },
      "VerifyRequest": {
        "type": "object",
        "required": [
          "userId",
          "code",
          "method"
        ],
        "properties": {
          "userId": {
            "type": "integer"
          },
          "code": {
            "type": "string"
          },
          "method": {
            "type": "string",
            "enum": [
              "email",
              "sms"
            ]
          }
        }
      },
      "ResetPasswordRequest": {
        "type": "object",
        "required": [
          "userId",
          "code",
          "newPassword"
        ],
        "properties": {
          "userId": {
            "type": "integer"
          },
          "code": {
            "type": "string"
          },
          "newPassword": {
            "type": "string",
            "minLength": 8
          },
          "method": {
            "type": "string",
            "enum": [
              "email",
              "sms"
            ],
            "default": "email"
          }
        }
      },
      "MFAVerifyRequest": {
        "type": "object",
        "required": [
          "userId",
          "verifications"
        ],
        "properties": {
          "userId": {
            "type": "integer"
          },
          "verifications": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "method",
                "code"
              ],
              "properties": {
                "method": {
                  "type": "string",
                  "enum": [
                    "email",
                    "sms",
                    "authenticator"
                  ]
                },
                "code": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "BusinessCreateRequest": {
        "type": "object",
        "required": [
          "name",
          "businessSlug"
        ],
        "properties": {
          "name": {
            "type": "string",
            "minLength": 2,
            "maxLength": 100
          },
          "businessSlug": {
            "type": "string",
            "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$"
          },
          "description": {
            "type": "string",
            "maxLength": 500
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "phone": {
            "type": "string"
          },
          "address": {
            "type": "string"
          },
          "website": {
            "type": "string"
          }
        }
      },
      "BusinessUpdateRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 2,
            "maxLength": 100
          },
          "description": {
            "type": "string",
            "maxLength": 500
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "phone": {
            "type": "string"
          },
          "address": {
            "type": "string"
          },
          "website": {
            "type": "string"
          }
        }
      },
      "AuthResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "data": {
            "type": "object",
            "properties": {
              "token": {
                "type": "string"
              },
              "type": {
                "type": "string",
                "default": "Bearer"
              },
              "expiresIn": {
                "type": "string"
              },
              "user": {
                "$ref": "#/components/schemas/User"
              },
              "sessionId": {
                "type": "string"
              },
              "verificationRequired": {
                "type": "boolean"
              },
              "requiresMFA": {
                "type": "boolean"
              },
              "challenges": {
                "type": "array",
                "items": {}
              }
            }
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "SuccessResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "message": {
            "type": "string"
          },
          "data": {
            "type": "object"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "default": false
          },
          "error": {
            "type": "object",
            "properties": {
              "message": {
                "type": "string"
              },
              "code": {
                "type": "string"
              },
              "details": {
                "type": "object"
              }
            }
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "TokenVerifyResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "data": {
            "type": "object",
            "properties": {
              "valid": {
                "type": "boolean"
              },
              "user": {
                "type": "object"
              }
            }
          },
          "message": {
            "type": "string"
          }
        }
      },
      "BusinessResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "data": {
            "$ref": "#/components/schemas/Business"
          }
        }
      },
      "BusinessUsersResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "data": {
            "type": "object",
            "properties": {
              "users": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/BusinessUser"
                }
              }
            }
          }
        }
      },
      "UserListResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/User"
            }
          },
          "pagination": {
            "type": "object",
            "properties": {
              "page": {
                "type": "integer"
              },
              "limit": {
                "type": "integer"
              },
              "total": {
                "type": "integer"
              },
              "pages": {
                "type": "integer"
              }
            }
          }
        }
      },
      "User": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "email": {
            "type": "string"
          },
          "phoneNumber": {
            "type": "string"
          },
          "firstName": {
            "type": "string"
          },
          "lastName": {
            "type": "string"
          },
          "username": {
            "type": "string"
          },
          "emailVerified": {
            "type": "boolean"
          },
          "phoneVerified": {
            "type": "boolean"
          },
          "mfaEnabled": {
            "type": "boolean"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Business": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "slug": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "phone": {
            "type": "string"
          },
          "address": {
            "type": "string"
          },
          "website": {
            "type": "string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "BusinessUser": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "email": {
            "type": "string"
          },
          "firstName": {
            "type": "string"
          },
          "lastName": {
            "type": "string"
          },
          "roleId": {
            "type": "integer"
          },
          "roleName": {
            "type": "string"
          },
          "joinedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Role": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "isBusinessRole": {
            "type": "boolean"
          }
        }
      },
      "Permission": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "resource": {
            "type": "string"
          },
          "action": {
            "type": "string"
          }
        }
      },
      "PermissionsResponse": {
        "type": "object",
        "properties": {
          "businessId": {
            "type": "integer"
          },
          "businessName": {
            "type": "string"
          },
          "businessSlug": {
            "type": "string"
          },
          "roles": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "isOwner": {
            "type": "boolean"
          },
          "isGlobalAdmin": {
            "type": "boolean"
          },
          "permissions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "permissionsDetailed": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string"
                },
                "description": {
                  "type": "string"
                },
                "source": {
                  "type": "string",
                  "enum": [
                    "role",
                    "delegated",
                    "global_admin"
                  ]
                },
                "grantedBy": {
                  "type": "string"
                },
                "expiresAt": {
                  "type": "string",
                  "format": "date-time"
                }
              }
            }
          },
          "permissionsByCategory": {
            "type": "object"
          },
          "totalPermissions": {
            "type": "integer"
          },
          "hasDelegatedPermissions": {
            "type": "boolean"
          }
        }
      },
      "PermissionCheckResponse": {
        "type": "object",
        "properties": {
          "hasPermission": {
            "type": "boolean"
          },
          "userId": {
            "type": "integer"
          },
          "businessId": {
            "type": "integer"
          },
          "permissionName": {
            "type": "string"
          }
        }
      },
      "AvailablePermissionsResponse": {
        "type": "object",
        "properties": {
          "permissions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "permissionsByCategory": {
            "type": "object"
          },
          "totalPermissions": {
            "type": "integer"
          }
        }
      },
      "ActiveBusinessResponse": {
        "type": "object",
        "properties": {
          "message": {
            "type": "string"
          },
          "token": {
            "type": "string"
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time"
          },
          "sessionId": {
            "type": "string"
          },
          "activeBusiness": {
            "$ref": "#/components/schemas/Business"
          },
          "activeBusinessId": {
            "type": "integer"
          }
        }
      }
    }
  }
}