{
  "openapi": "3.0.3",
  "info": {
    "title": "InsightSentry Organization API",
    "version": "1.0.0",
    "description": "Manage organization members, access, and credits.",
    "contact": {
      "name": "InsightSentry Support",
      "email": "support@insightsentry.com"
    }
  },
  "servers": [
    {
      "url": "https://insightsentry.com"
    }
  ],
  "security": [
    {
      "OrganizationApiKey": []
    }
  ],
  "tags": [
    {
      "name": "Plans"
    },
    {
      "name": "Members"
    }
  ],
  "externalDocs": {
    "description": "Organization API documentation",
    "url": "https://insightsentry.com/docs/organization"
  },
  "paths": {
    "/api/organization/plans": {
      "get": {
        "tags": [
          "Plans"
        ],
        "operationId": "getOrganizationPlans",
        "summary": "List organization plans",
        "responses": {
          "200": {
            "description": "List organization plans.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PlansResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/api/organization/members": {
      "get": {
        "tags": [
          "Members"
        ],
        "operationId": "listOrganizationMembers",
        "summary": "List organization members",
        "responses": {
          "200": {
            "description": "List organization members.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MemberListResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50,
              "default": 50
            }
          }
        ]
      }
    },
    "/api/organization/members/create": {
      "post": {
        "tags": [
          "Members"
        ],
        "operationId": "createOrganizationMember",
        "summary": "Create a member",
        "description": "Create a member and purchase access using organization credits.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateMemberRequest"
              },
              "example": {
                "uid": "john_doe",
                "plan": "pro",
                "full_name": "John Doe",
                "months": 1
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Create a member.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MemberResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/InsufficientCredits"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/api/organization/members/get": {
      "post": {
        "tags": [
          "Members"
        ],
        "operationId": "getOrganizationMember",
        "summary": "Get a member",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MemberSelector"
              },
              "example": {
                "uid": "john_doe"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Get a member.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MemberResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/api/organization/members/update": {
      "post": {
        "tags": [
          "Members"
        ],
        "operationId": "updateOrganizationMember",
        "summary": "Update a member",
        "description": "Unchanged plan and addons renew access. Inactive access starts a new period. Active plan and addon changes are prorated.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateMemberRequest"
              },
              "example": {
                "uid": "john_doe",
                "plan": "pro",
                "months": 1
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Update a member.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UpdateMemberResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/InsufficientCredits"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/api/organization/members/cancel": {
      "post": {
        "tags": [
          "Members"
        ],
        "operationId": "cancelOrganizationMember",
        "summary": "Cancel member access",
        "description": "End access immediately and refund the remaining value less a 10% fee.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MemberSelector"
              },
              "example": {
                "uid": "john_doe"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Cancel member access.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CancelMemberResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/api/organization/members/delete": {
      "post": {
        "tags": [
          "Members"
        ],
        "operationId": "deleteOrganizationMember",
        "summary": "Delete a member",
        "description": "Remove a member after access is canceled or expires. The UID remains reserved.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MemberSelector"
              },
              "example": {
                "uid": "john_doe"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Delete a member.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeleteMemberResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "OrganizationApiKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "Organization API key from the dashboard Organization tab."
      }
    },
    "schemas": {
      "MemberUid": {
        "type": "string",
        "minLength": 1,
        "maxLength": 100,
        "pattern": "^[A-Za-z0-9_!/.=-]+$",
        "description": "Member identifier.",
        "example": "john_doe"
      },
      "AddonQuantities": {
        "type": "object",
        "properties": {
          "websocket": {
            "type": "integer",
            "minimum": 0,
            "maximum": 10
          },
          "rate_limit": {
            "type": "integer",
            "minimum": 0,
            "maximum": 20
          }
        },
        "description": "Addon quantities. Omitted quantities default to zero on creation and stay unchanged on update."
      },
      "MemberAddons": {
        "type": "object",
        "properties": {
          "websocket": {
            "type": "integer",
            "minimum": 0,
            "maximum": 10
          },
          "rate_limit": {
            "type": "integer",
            "minimum": 0,
            "maximum": 20
          }
        },
        "required": [
          "websocket",
          "rate_limit"
        ]
      },
      "MemberSelector": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "format": "email",
            "description": "Member email returned by the API.",
            "example": "org_john_doe@example.com"
          },
          "uid": {
            "$ref": "#/components/schemas/MemberUid"
          }
        },
        "oneOf": [
          {
            "required": [
              "email"
            ],
            "type": "object",
            "properties": {
              "email": {
                "type": "string",
                "format": "email",
                "description": "Member email returned by the API.",
                "example": "org_john_doe@example.com"
              }
            }
          },
          {
            "required": [
              "uid"
            ],
            "type": "object",
            "properties": {
              "uid": {
                "$ref": "#/components/schemas/MemberUid"
              }
            }
          }
        ],
        "description": "Provide exactly one of email or uid."
      },
      "CreateMemberRequest": {
        "type": "object",
        "properties": {
          "uid": {
            "$ref": "#/components/schemas/MemberUid"
          },
          "plan": {
            "type": "string",
            "minLength": 1,
            "description": "pro, ultra, mega, or a custom plan name returned by /plans.",
            "example": "pro"
          },
          "full_name": {
            "type": "string"
          },
          "months": {
            "type": "integer",
            "minimum": 1,
            "maximum": 12,
            "default": 1,
            "description": "Number of 31-day access periods."
          },
          "addons": {
            "$ref": "#/components/schemas/AddonQuantities"
          }
        },
        "required": [
          "uid",
          "plan"
        ]
      },
      "UpdateMemberRequest": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "format": "email",
            "description": "Member email returned by the API.",
            "example": "org_john_doe@example.com"
          },
          "uid": {
            "$ref": "#/components/schemas/MemberUid"
          },
          "plan": {
            "type": "string",
            "minLength": 1,
            "description": "pro, ultra, mega, or a custom plan name returned by /plans.",
            "example": "pro"
          },
          "full_name": {
            "type": "string"
          },
          "months": {
            "type": "integer",
            "minimum": 1,
            "maximum": 12,
            "default": 1,
            "description": "Number of 31-day access periods."
          },
          "addons": {
            "$ref": "#/components/schemas/AddonQuantities"
          }
        },
        "oneOf": [
          {
            "required": [
              "email"
            ],
            "type": "object",
            "properties": {
              "email": {
                "type": "string",
                "format": "email",
                "description": "Member email returned by the API.",
                "example": "org_john_doe@example.com"
              }
            }
          },
          {
            "required": [
              "uid"
            ],
            "type": "object",
            "properties": {
              "uid": {
                "$ref": "#/components/schemas/MemberUid"
              }
            }
          }
        ],
        "anyOf": [
          {
            "required": [
              "plan"
            ],
            "properties": {
              "plan": {
                "type": "string",
                "minLength": 1,
                "description": "pro, ultra, mega, or a custom plan name returned by /plans.",
                "example": "pro"
              }
            },
            "type": "object"
          },
          {
            "required": [
              "full_name"
            ],
            "properties": {
              "full_name": {
                "type": "string",
                "minLength": 1
              }
            },
            "type": "object"
          },
          {
            "required": [
              "addons"
            ],
            "properties": {
              "addons": {
                "$ref": "#/components/schemas/AddonQuantities"
              }
            },
            "type": "object"
          }
        ],
        "description": "Provide one member selector and at least one of plan, full_name, or addons. Months applies to renewal or restoration."
      },
      "Member": {
        "type": "object",
        "properties": {
          "uid": {
            "type": "string"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "full_name": {
            "type": "string",
            "nullable": true
          },
          "role": {
            "type": "string",
            "enum": [
              "member"
            ]
          },
          "access_model": {
            "type": "string",
            "enum": [
              "organization_managed"
            ]
          },
          "plan": {
            "type": "string",
            "description": "Base feature tier.",
            "example": "pro"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "inactive",
              "canceled"
            ]
          },
          "created_at": {
            "type": "string",
            "description": "Creation time.",
            "example": "2026-09-11T00:00:00.000Z"
          },
          "plan_end_at": {
            "type": "string",
            "nullable": true,
            "description": "Access expiration time."
          },
          "custom_plan_name": {
            "type": "string",
            "nullable": true
          },
          "addons": {
            "$ref": "#/components/schemas/MemberAddons"
          },
          "api_key": {
            "type": "string",
            "description": "Member API key, when available."
          },
          "websocket_symbols": {
            "type": "integer"
          },
          "websocket_connections": {
            "type": "integer"
          },
          "newsfeed": {
            "type": "boolean"
          },
          "rate_limit": {
            "type": "integer",
            "description": "Requests per minute."
          },
          "quota": {
            "type": "integer"
          },
          "quota_exceeded": {
            "type": "boolean"
          },
          "quota_reset_time": {
            "type": "string"
          },
          "override_rate_limit": {
            "type": "integer",
            "description": "Requests per minute."
          },
          "override_websocket_connections": {
            "type": "integer"
          },
          "override_websocket_symbols": {
            "type": "integer"
          },
          "override_quota": {
            "type": "integer"
          },
          "custom_price_used": {
            "type": "number",
            "description": "Monthly plan price in credits."
          }
        },
        "required": [
          "uid",
          "email",
          "full_name",
          "role",
          "access_model",
          "plan",
          "status",
          "created_at",
          "plan_end_at",
          "custom_plan_name",
          "addons"
        ]
      },
      "MemberResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "enum": [
              true
            ]
          },
          "member": {
            "$ref": "#/components/schemas/Member"
          }
        },
        "required": [
          "success",
          "member"
        ]
      },
      "Pagination": {
        "type": "object",
        "properties": {
          "page": {
            "type": "integer",
            "minimum": 1
          },
          "limit": {
            "type": "integer",
            "minimum": 1,
            "maximum": 50
          },
          "total": {
            "type": "integer",
            "minimum": 0
          },
          "total_pages": {
            "type": "integer",
            "minimum": 0
          }
        },
        "required": [
          "page",
          "limit",
          "total",
          "total_pages"
        ]
      },
      "MemberListResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "enum": [
              true
            ]
          },
          "members": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Member"
            }
          },
          "pagination": {
            "$ref": "#/components/schemas/Pagination"
          }
        },
        "required": [
          "success",
          "members",
          "pagination"
        ]
      },
      "Proration": {
        "type": "object",
        "properties": {
          "old_plan": {
            "type": "string"
          },
          "new_plan": {
            "type": "string"
          },
          "credit_adjustment": {
            "type": "number",
            "description": "Prorated credits before the 10% fee. Negative values are charges."
          },
          "days_remaining": {
            "type": "integer",
            "minimum": 0
          }
        },
        "required": [
          "old_plan",
          "new_plan",
          "credit_adjustment",
          "days_remaining"
        ]
      },
      "Renewal": {
        "type": "object",
        "properties": {
          "plan": {
            "type": "string"
          },
          "amount_charged": {
            "type": "number",
            "minimum": 0,
            "description": "Credits charged."
          },
          "extended_days": {
            "type": "integer",
            "minimum": 31
          },
          "new_expiration": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "plan",
          "amount_charged",
          "extended_days",
          "new_expiration"
        ]
      },
      "UpdateMemberResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "enum": [
              true
            ]
          },
          "member": {
            "$ref": "#/components/schemas/Member"
          },
          "proration": {
            "$ref": "#/components/schemas/Proration"
          },
          "renewal": {
            "$ref": "#/components/schemas/Renewal"
          }
        },
        "required": [
          "success",
          "member"
        ]
      },
      "Refund": {
        "type": "object",
        "properties": {
          "amount": {
            "type": "number",
            "minimum": 0,
            "description": "Credits refunded after the fee."
          },
          "fee": {
            "type": "number",
            "minimum": 0,
            "description": "Cancellation fee in credits."
          },
          "original_remaining_value": {
            "type": "number",
            "minimum": 0,
            "description": "Remaining credits before the fee."
          },
          "days_refunded": {
            "type": "integer",
            "minimum": 0
          }
        },
        "required": [
          "amount",
          "fee",
          "original_remaining_value",
          "days_refunded"
        ]
      },
      "CancelMemberResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "enum": [
              true
            ]
          },
          "message": {
            "type": "string"
          },
          "refund": {
            "$ref": "#/components/schemas/Refund"
          }
        },
        "required": [
          "success",
          "message",
          "refund"
        ]
      },
      "DeleteMemberResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "enum": [
              true
            ]
          },
          "message": {
            "type": "string"
          }
        },
        "required": [
          "success",
          "message"
        ]
      },
      "RegularPlan": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "enum": [
              "pro",
              "ultra",
              "mega"
            ]
          },
          "price": {
            "type": "number",
            "description": "Monthly price in credits."
          }
        },
        "required": [
          "name",
          "price"
        ]
      },
      "CustomPlan": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "feature": {
            "type": "string",
            "enum": [
              "pro",
              "ultra",
              "mega"
            ]
          },
          "price": {
            "type": "number",
            "description": "Monthly price in credits."
          },
          "rate_limit": {
            "type": "integer",
            "nullable": true,
            "description": "Requests per minute."
          },
          "websocket_connections": {
            "type": "integer",
            "nullable": true
          },
          "websocket_symbols": {
            "type": "integer",
            "nullable": true
          },
          "quota": {
            "type": "integer",
            "nullable": true
          },
          "created_at": {
            "type": "string"
          },
          "updated_at": {
            "type": "string"
          },
          "admin_email": {
            "type": "string",
            "format": "email"
          }
        },
        "required": [
          "name",
          "feature",
          "price"
        ]
      },
      "Addon": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "enum": [
              "websocket",
              "rate_limit"
            ]
          },
          "price": {
            "type": "number",
            "description": "Monthly price per addon quantity in credits."
          },
          "step": {
            "type": "integer"
          },
          "unit": {
            "type": "string"
          },
          "max_quantity": {
            "type": "integer"
          },
          "eligible_plans": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "name",
          "price",
          "step",
          "unit",
          "max_quantity",
          "eligible_plans"
        ]
      },
      "PlansResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "enum": [
              true
            ]
          },
          "regular_plans": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RegularPlan"
            }
          },
          "custom_plans": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CustomPlan"
            }
          },
          "addons": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Addon"
            }
          }
        },
        "required": [
          "success",
          "regular_plans",
          "custom_plans",
          "addons"
        ]
      },
      "Error": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "enum": [
              false
            ]
          },
          "error": {
            "type": "string"
          }
        },
        "required": [
          "success",
          "error"
        ]
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Invalid request.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Invalid or missing organization API key.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "InsufficientCredits": {
        "description": "Insufficient credits.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "NotFound": {
        "description": "Member not found.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Conflict": {
        "description": "Request conflicts with the member state.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "TooManyRequests": {
        "description": "Too many requests.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "InternalError": {
        "description": "Unable to complete the request.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Unavailable": {
        "description": "Service temporarily unavailable.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    }
  }
}
