openapi: 3.0.2
info:
  title: Claromentis People API
  description: Claromentis People API v2, Open API v3 specification.
  version: 2.0.0
  contact:
    name: Discover Claromentis
    url: https://discover.claromentis.com
externalDocs:
  description: Learn more about Claromentis APIs
  url: https://developer.claromentis.com
servers:
  - url: '{Protocol}{Hostname}/api/people/v2'
    variables:
      Protocol:
        enum:
          - https://
          - http://
        default: https://
      Hostname:
        default: 'yourintranet.com'
        description: Claromentis Server Hostname
security:
  - HttpBasic: []
tags:
  - name: Users
    description: Users can log in, belong to Groups and Roles, and must belong to an Extranet
  - name: Groups
    description: Groups can be assigned Users, belong to a parent Group, and belong to an Extranet
  - name: Roles
    description: Roles can be assigned Users and belong to an Extranet
  - name: Extranets
    description: Extranets can be assigned Users, Groups and Roles
  - name: Contacts
    description: Contacts belong to Users
paths:
  # User paths
  /user:
    get:
      tags:
        - Users
      summary: Get the currently authenticated User
      responses:
        200:
          $ref: '#/components/responses/User'
  /users:
    get:
      tags:
        - Users
      summary: Get a collection of Users
      parameters:
        - $ref: '#/components/parameters/IDs'
        - $ref: '#/components/parameters/GroupIDs'
        - $ref: '#/components/parameters/RoleIDs'
        - $ref: '#/components/parameters/ExtranetID'
        - $ref: '#/components/parameters/View'
        - $ref: '#/components/parameters/Status'
        - $ref: '#/components/parameters/Online'
        - $ref: '#/components/parameters/Fields'
        - $ref: '#/components/parameters/Query'
        - $ref: '#/components/parameters/QueryFields'
        - $ref: '#/components/parameters/QueryType'
        - $ref: '#/components/parameters/Sort'
        - $ref: '#/components/parameters/SortDirection'
        - $ref: '#/components/parameters/Limit'
        - $ref: '#/components/parameters/Offset'
      responses:
        200:
          $ref: "#/components/responses/PaginatedUsers"
    post:
      tags:
        - Users
      summary: Create a new User
      requestBody:
        $ref: '#/components/requestBodies/User'
      responses:
        201:
          $ref: '#/components/responses/User'
  /users/{id}:
    parameters:
      - $ref: '#/components/parameters/ID'
    get:
      tags:
        - Users
      summary: Get a User
      parameters:
        - $ref: '#/components/parameters/Fields'
      responses:
        200:
          $ref: '#/components/responses/User'
        404:
          description: User not found
    put:
      tags:
        - Users
      summary: Update a User
      description: All fields are optional when updating a User.
      requestBody:
        $ref: '#/components/requestBodies/User'
      responses:
        200:
          $ref: '#/components/responses/User'
        404:
          description: User not found
    delete:
      tags:
        - Users
      summary: Delete a User
      description: When deleting a User, provide a `reassign_user_id` to reassign their data to another User. Otherwise, their data will be deleted.
      parameters:
        - name: reassign_user_id
          in: query
          schema:
            type: integer
          description: User ID to reassign data to
      responses:
        204:
          $ref: '#/components/responses/Deleted'
        404:
          description: User not found
  /users/{id}/photo:
    parameters:
      - $ref: '#/components/parameters/ID'
    post:
      tags:
        - Users
      summary: Update a User's photo
      requestBody:
        content:
          multipart/form-data:
            schema:
              type: object
              required:
                - photo
              properties:
                x:
                  type: integer
                  description: Crop X coordinate in pixels
                  example: 0
                y:
                  type: integer
                  description: Crop Y coordinate in pixels
                  example: 0
                width:
                  type: integer
                  description: Crop width in pixels
                  example: 0
                photo:
                  type: string
                  description: The image to set as the user's profile photo
                  format: binary
      responses:
        200:
          description: User photo updated successfully
        404:
          description: User not found
    delete:
      tags:
        - Users
      summary: Delete a User's photo
      responses:
        204:
          description: User photo deleted successfully
        404:
          description: User not found
  /users/{id}/password:
    parameters:
      - $ref: '#/components/parameters/ID'
    put:
      tags:
        - Users
      summary: Set a User's password
      description: If you do not have administrator permissions to edit a user, the password will be subject to the password policy as configured in the People application.
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
                - password
              properties:
                password:
                  type: string
      responses:
        204:
          description: User password updated successfully
        400:
          description: Password is invalid
        404:
          description: User not found
  /users/{id}/manager:
    parameters:
      - $ref: '#/components/parameters/ID'
    put:
      tags:
        - Users
      summary: Set a User's manager
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
                - manager_id
              properties:
                manager_id:
                  type: integer
      responses:
        200:
          $ref: '#/components/responses/User'
        400:
          description: Manager ID is required
        404:
          description: User not found
  /users/{id}/subordinates:
    parameters:
      - $ref: '#/components/parameters/ID'
    get:
      tags:
        - Users
      summary: Get a collection of a User's subordinates
      parameters:
        - $ref: '#/components/parameters/GroupIDs'
        - $ref: '#/components/parameters/RoleIDs'
        - $ref: '#/components/parameters/ExtranetID'
        - $ref: '#/components/parameters/View'
        - $ref: '#/components/parameters/Status'
        - $ref: '#/components/parameters/Online'
        - $ref: '#/components/parameters/Fields'
        - $ref: '#/components/parameters/Query'
        - $ref: '#/components/parameters/QueryFields'
        - $ref: '#/components/parameters/QueryType'
        - $ref: '#/components/parameters/Sort'
        - $ref: '#/components/parameters/SortDirection'
        - $ref: '#/components/parameters/Limit'
        - $ref: '#/components/parameters/Offset'
      responses:
        200:
          $ref: '#/components/responses/PaginatedUsers'
        404:
          description: User not found
    put:
      tags:
        - Users
      summary: Set a User's subordinates
      requestBody:
        $ref: '#/components/requestBodies/IDs'
      responses:
        200:
          $ref: '#/components/responses/Users'
        404:
          description: User not found
  /users/{id}/groups:
    parameters:
      - $ref: '#/components/parameters/ID'
    get:
      tags:
        - Users
      summary: Get a collection of a User's groups
      parameters:
        - $ref: '#/components/parameters/ParentID'
        - $ref: '#/components/parameters/OwnerID'
        - $ref: '#/components/parameters/ExtranetID'
        - $ref: '#/components/parameters/UserIDs'
        - $ref: '#/components/parameters/Fields'
        - $ref: '#/components/parameters/Query'
        - $ref: '#/components/parameters/QueryFields'
        - $ref: '#/components/parameters/QueryType'
        - $ref: '#/components/parameters/Sort'
        - $ref: '#/components/parameters/SortDirection'
        - $ref: '#/components/parameters/Limit'
        - $ref: '#/components/parameters/Offset'
      responses:
        200:
          $ref: '#/components/responses/PaginatedGroups'
        404:
          description: User not found
    put:
      tags:
        - Users
      summary: Set a User's groups
      requestBody:
        $ref: '#/components/requestBodies/IDs'
      responses:
        200:
          $ref: '#/components/responses/Groups'
        404:
          description: User not found
  /users/{id}/roles:
    parameters:
      - $ref: '#/components/parameters/ID'
    get:
      tags:
        - Users
      summary: Get a collection of a User's roles
      parameters:
        - $ref: '#/components/parameters/OwnerID'
        - $ref: '#/components/parameters/ExtranetID'
        - $ref: '#/components/parameters/UserIDs'
        - $ref: '#/components/parameters/Fields'
        - $ref: '#/components/parameters/Query'
        - $ref: '#/components/parameters/QueryFields'
        - $ref: '#/components/parameters/QueryType'
        - $ref: '#/components/parameters/Sort'
        - $ref: '#/components/parameters/SortDirection'
        - $ref: '#/components/parameters/Limit'
        - $ref: '#/components/parameters/Offset'
      responses:
        200:
          $ref: '#/components/responses/PaginatedRoles'
        404:
          description: User not found
    put:
      tags:
        - Users
      summary: Set a User's roles
      requestBody:
        $ref: '#/components/requestBodies/IDs'
      responses:
        200:
          $ref: '#/components/responses/Roles'
        404:
          description: User not found

  # Group paths
  /groups:
    get:
      tags:
        - Groups
      summary: Get a collection of Groups
      parameters:
        - $ref: '#/components/parameters/IDs'
        - $ref: '#/components/parameters/ParentID'
        - $ref: '#/components/parameters/OwnerID'
        - $ref: '#/components/parameters/ExtranetID'
        - $ref: '#/components/parameters/UserIDs'
        - $ref: '#/components/parameters/Fields'
        - $ref: '#/components/parameters/Query'
        - $ref: '#/components/parameters/QueryFields'
        - $ref: '#/components/parameters/QueryType'
        - $ref: '#/components/parameters/Sort'
        - $ref: '#/components/parameters/SortDirection'
        - $ref: '#/components/parameters/Limit'
        - $ref: '#/components/parameters/Offset'
      responses:
        200:
          $ref: '#/components/responses/PaginatedGroups'
    post:
      tags:
        - Groups
      summary: Create a new Group
      requestBody:
        $ref: '#/components/requestBodies/Group'
      responses:
        201:
          $ref: '#/components/responses/Group'
  /groups/{id}:
    parameters:
      - $ref: '#/components/parameters/ID'
    get:
      tags:
        - Groups
      summary: Get a Group
      parameters:
        - $ref: '#/components/parameters/Fields'
      responses:
        200:
          $ref: '#/components/responses/Group'
        404:
          description: Group not found
    put:
      tags:
        - Groups
      summary: Update a Group
      requestBody:
        $ref: '#/components/requestBodies/Group'
      responses:
        200:
          $ref: '#/components/responses/Group'
        404:
          description: Group not found
    delete:
      tags:
        - Groups
      summary: Delete a Group
      responses:
        204:
          $ref: '#/components/responses/Deleted'
        404:
          description: Group not found
  /groups/{id}/users:
    parameters:
      - $ref: '#/components/parameters/ID'
    get:
      tags:
        - Groups
      summary: Get a collection of Users that belong to a Group
      parameters:
        - $ref: '#/components/parameters/View'
        - $ref: '#/components/parameters/Status'
        - $ref: '#/components/parameters/Online'
        - $ref: '#/components/parameters/Fields'
        - $ref: '#/components/parameters/Query'
        - $ref: '#/components/parameters/QueryFields'
        - $ref: '#/components/parameters/QueryType'
        - $ref: '#/components/parameters/Sort'
        - $ref: '#/components/parameters/SortDirection'
        - $ref: '#/components/parameters/Limit'
        - $ref: '#/components/parameters/Offset'
      responses:
        200:
          $ref: '#/components/responses/PaginatedUsers'
        404:
          description: Group not found
    put:
      tags:
        - Groups
      summary: Set the Users that belong to a Group
      requestBody:
        $ref: '#/components/requestBodies/IDs'
      responses:
        200:
          $ref: '#/components/responses/Users'
        404:
          description: Role not found

  # Role paths
  /roles:
    get:
      tags:
        - Roles
      summary: Get a collection of Roles
      parameters:
        - $ref: '#/components/parameters/IDs'
        - $ref: '#/components/parameters/OwnerID'
        - $ref: '#/components/parameters/ExtranetID'
        - $ref: '#/components/parameters/UserIDs'
        - $ref: '#/components/parameters/Fields'
        - $ref: '#/components/parameters/Query'
        - $ref: '#/components/parameters/QueryFields'
        - $ref: '#/components/parameters/QueryType'
        - $ref: '#/components/parameters/Sort'
        - $ref: '#/components/parameters/SortDirection'
        - $ref: '#/components/parameters/Limit'
        - $ref: '#/components/parameters/Offset'
      responses:
        200:
          $ref: '#/components/responses/PaginatedRoles'
    post:
      tags:
        - Roles
      summary: Create a new Role
      requestBody:
        $ref: '#/components/requestBodies/Role'
      responses:
        201:
          $ref: '#/components/responses/Role'
  /roles/{id}:
    parameters:
      - $ref: '#/components/parameters/ID'
    get:
      tags:
        - Roles
      summary: Get a Role
      parameters:
        - $ref: '#/components/parameters/Fields'
      responses:
        200:
          $ref: '#/components/responses/Role'
        404:
          description: Role not found
    put:
      tags:
        - Roles
      summary: Update a Role
      requestBody:
        $ref: '#/components/requestBodies/Role'
      responses:
        200:
          $ref: '#/components/responses/Role'
        404:
          description: Role not found
    delete:
      tags:
        - Roles
      summary: Delete a Role
      responses:
        204:
          $ref: '#/components/responses/Deleted'
        404:
          description: Role not found
  /roles/{id}/users:
    parameters:
      - $ref: '#/components/parameters/ID'
    get:
      tags:
        - Roles
      summary: Get a collection of Users that belong to a Role
      parameters:
        - $ref: '#/components/parameters/View'
        - $ref: '#/components/parameters/Status'
        - $ref: '#/components/parameters/Online'
        - $ref: '#/components/parameters/Fields'
        - $ref: '#/components/parameters/Query'
        - $ref: '#/components/parameters/QueryFields'
        - $ref: '#/components/parameters/QueryType'
        - $ref: '#/components/parameters/Sort'
        - $ref: '#/components/parameters/SortDirection'
        - $ref: '#/components/parameters/Limit'
        - $ref: '#/components/parameters/Offset'
      responses:
        200:
          $ref: '#/components/responses/PaginatedUsers'
        404:
          description: Role not found
    put:
      tags:
        - Roles
      summary: Set the Users that belong to a Role
      requestBody:
        $ref: '#/components/requestBodies/IDs'
      responses:
        200:
          $ref: '#/components/responses/Users'
        404:
          description: Role not found

  # Extranet paths
  /extranets:
    get:
      tags:
        - Extranets
      summary: Get a collection of Extranets
      parameters:
        - $ref: '#/components/parameters/IDs'
        - $ref: '#/components/parameters/Fields'
        - $ref: '#/components/parameters/Query'
        - $ref: '#/components/parameters/QueryFields'
        - $ref: '#/components/parameters/QueryType'
        - $ref: '#/components/parameters/Sort'
        - $ref: '#/components/parameters/SortDirection'
        - $ref: '#/components/parameters/Limit'
        - $ref: '#/components/parameters/Offset'
      responses:
        200:
          $ref: '#/components/responses/PaginatedExtranets'
    post:
      tags:
        - Extranets
      summary: Create a new Extranet
      requestBody:
        $ref: '#/components/requestBodies/Extranet'
      responses:
        201:
          $ref: '#/components/responses/Extranet'
  /extranets/{id}:
    parameters:
      - $ref: '#/components/parameters/ID'
    get:
      tags:
        - Extranets
      summary: Get an Extranet
      responses:
        200:
          $ref: '#/components/responses/Extranet'
        404:
          description: Extranet not found
    put:
      tags:
        - Extranets
      summary: Update an Extranet
      description: The Primary Extranet can only be changed via this endpoint by setting a different Extranet's `primary` property to `true`.
      requestBody:
        $ref: '#/components/requestBodies/Extranet'
      responses:
        200:
          $ref: '#/components/responses/Extranet'
        404:
          description: Extranet not found
    delete:
      tags:
        - Extranets
      summary: Delete an Extranet
      description: The Primary Extranet cannot be deleted. Other Extranets cannot be deleted without providing a `new_extranet_id` if they contain Users.
      parameters:
        - name: new_extranet_id
          in: query
          schema:
            type: integer
          description: The ID of the Extranet to move Users to.
      responses:
        204:
          description: Extranet deleted successfully
        400:
          description: Extranet cannot be deleted
        404:
          description: Extranet not found
  /extranets/{id}/users:
    parameters:
      - $ref: '#/components/parameters/ID'
    get:
      tags:
        - Extranets
      summary: Get the Users that belong to an Extranet
      parameters:
        - $ref: '#/components/parameters/View'
        - $ref: '#/components/parameters/Status'
        - $ref: '#/components/parameters/Online'
        - $ref: '#/components/parameters/Fields'
        - $ref: '#/components/parameters/Query'
        - $ref: '#/components/parameters/QueryFields'
        - $ref: '#/components/parameters/QueryType'
        - $ref: '#/components/parameters/Sort'
        - $ref: '#/components/parameters/SortDirection'
        - $ref: '#/components/parameters/Limit'
        - $ref: '#/components/parameters/Offset'
      responses:
        200:
          $ref: '#/components/responses/PaginatedUsers'
        404:
          description: Extranet not found
    put:
      tags:
        - Extranets
      summary: Add Users to an Extranet
      description: Unlike other collection subresource `PUT` endpoints in the API, this _moves_ users to an Extranet without removing any, instead of _setting_ them absolutely. This is because Users _must_ belong to an extranet.
      requestBody:
        $ref: '#/components/requestBodies/IDs'
      responses:
        200:
          $ref: '#/components/responses/Users'
        404:
          description: Extranet not found
  /extranets/primary:
    get:
      tags:
        - Extranets
      summary: Get the Primary Extranet
      responses:
        200:
          $ref: '#/components/responses/Extranet'

  # Contact paths
  /contacts:
    get:
      tags:
        - Contacts
      summary: Get a collection of Contacts
      description: Responds with a list of 20 Contacts at a time.
      parameters:
        - name: exclude
          in: query
          schema:
            type: array
            items:
              type: integer
          explode: false
          description: Exclude the given comma-separated list of contact IDs from the results.
        - name: keywords
          in: query
          schema:
            type: string
          description: Search query
        - $ref: '#/components/parameters/Offset'
      responses:
        200:
          description: The Contacts
          content:
            application/json:
              schema:
                type: object
                properties:
                  contacts:
                    type: array
                    items:
                      $ref: '#/components/schemas/Contact'
                  total:
                    type: integer
                    description: The total number of Contacts
                    example: 100
    post:
      tags:
        - Contacts
      summary: Create a new Contact
      parameters:
        - name: name
          in: query
          schema:
            type: string
          description: Contact firstname, surname and email address provided in one string. Using this parameter overrides all of the others.
          examples:
            fullnameAndEmail:
              value: Jane Smith <jane.smith@consulting.co.uk>
              summary: Firstname, surname and email address
            firstnameAndEmail:
              value: Jane <jane.smith@consulting.co.uk>
              summary: Firstname and email address
            email:
              value: jane.smith@consulting.co.uk
              summary: Email address only
        - name: emailad
          in: query
          schema:
            type: string
            example: jane.smith@consulting.co.uk
          description: Contact email address. Must be unique amongst your personal contacts.
        - name: firstname
          in: query
          schema:
            type: string
            example: Jane
          description: Contact first name.
        - name: surname
          in: query
          schema:
            type: string
            example: Smith
          description: Contact surname.
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SimpleContact'
      responses:
        200:
          description: Contact created successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  contact:
                    $ref: '#/components/schemas/SimpleContact'
        400:
          description: Missing or incorrect email address

# Reusable components
components:

  # Reusable parameters
  parameters:
    ID:
      name: id
      in: path
      required: true
      schema:
        type: integer
        minimum: 0
        default: 0
      description: Object ID.
      example: 1
    IDs:
      name: ids
      in: query
      schema:
        type: array
        items:
          type: integer
      explode: false
      description: Comma-separated list of object IDs to filter by.
    Fields:
      name: fields
      in: query
      schema:
        type: array
        items:
          type: string
      explode: false
      description: Comma-separated list of fields to return. Fields that you do not have permission to view will be excluded from the results.
    Query:
      name: query
      in: query
      schema:
        type: string
      description: Search query keywords.
    QueryFields:
      name: query_fields
      in: query
      schema:
        type: array
        items:
          type: string
      explode: false
      description: Comma-separated list of fields to search. Fields that you do not have permission to view will be excluded from the search.
    QueryType:
      name: query_type
      in: query
      schema:
        type: string
        enum: [and, or]
      description: The logical comparison to make between search query keywords. `and` matches all keywords, `or` matches any keyword.
    Sort:
      name: sort
      in: query
      schema:
        type: string
      description: Field to sort by.
    SortDirection:
      name: sort_direction
      in: query
      schema:
        type: string
        enum: [asc, desc]
        default: asc
      description: Sort direction. `asc` is ascending order (A to Z), `desc` is descending order (Z to A).
    Status:
      name: status
      in: query
      schema:
        type: string
        enum: [active, blocked, all]
        default: active
      description: |
        User status to filter by: `active`, `blocked` or `all`.

        Blocked users will only be returned if the `view` parameter is set to `admin`.
    Online:
      name: online
      in: query
      schema:
        type: integer
        minimum: 0
        maximum: 1
      description: |
        Online user filter. `1` or `0`.

        - `1` will list online users
        - `0` will list offline users
    View:
      name: view
      in: query
      schema:
        type: string
        enum: [user, admin]
        default: user
      description: |
        User view context.

        - `user` will list users visible in a front-end context
        - `admin` will list users visible in an administrative context

        Administrative context enables the use of the `status` query parameter.
    UserIDs:
      name: user_ids
      in: query
      schema:
        type: array
        items:
          type: integer
      description: User IDs to filter by.
    GroupIDs:
      name: group_ids
      in: query
      schema:
        type: array
        items:
          type: integer
      explode: false
      description: Comma-separated list of Group IDs to filter by.
    RoleIDs:
      name: role_ids
      in: query
      schema:
        type: array
        items:
          type: integer
      explode: false
      description: Comma-separated list of Role IDs to filter by.
    ExtranetID:
      name: extranet_id
      in: query
      schema:
        type: integer
      description: Extranet ID to filter by.
    ParentID:
      name: parent_id
      in: query
      schema:
        type: integer
      description: Group parent ID to filter by.
    OwnerID:
      name: owner_id
      in: query
      schema:
        type: integer
      description: Object owner ID to filter by.
    Limit:
      name: limit
      in: query
      schema:
        type: integer
        minimum: 1
        maximum: 200
        default: 20
      description: The number of items to return.
    Offset:
      name: offset
      in: query
      schema:
        type: integer
      description: The number of items to offset results by.

  # Reusable request bodies
  requestBodies:
    IDs:
      description: Object IDs to associate
      content:
        application/json:
          schema:
            type: array
            items:
              type: object
              required:
                - id
              properties:
                id:
                  type: integer
    User:
      description: The User to persist
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/User'
    Group:
      description: The Group to persist
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Group'
    Role:
      description: The Role to persist
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Role'
    Extranet:
      description: The Extranet to persist
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Extranet'
    Contact:
      description: The Contact to persist
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Contact'

  # Reusable responses
  responses:
    User:
      description: The matching User
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/User'
    Users:
      description: The affected Users
      content:
        application/json:
          schema:
            type: array
            items:
              $ref: '#/components/schemas/User'
    PaginatedUsers:
      description: The Users matching the query
      content:
        application/json:
          schema:
            type: object
            properties:
              data:
                type: array
                items:
                  $ref: '#/components/schemas/User'
              pagination:
                $ref: '#/components/schemas/Pagination'
    Group:
      description: The matching Group
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Group'
    Groups:
      description: The affected Groups
      content:
        application/json:
          schema:
            type: array
            items:
              $ref: '#/components/schemas/Group'
    PaginatedGroups:
      description: The Groups matching the query
      content:
        application/json:
          schema:
            type: object
            properties:
              data:
                type: array
                items:
                  $ref: '#/components/schemas/Group'
              pagination:
                $ref: '#/components/schemas/Pagination'
    Role:
      description: The matching Role
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Role'
    Roles:
      description: The affected Roles
      content:
        application/json:
          schema:
            type: array
            items:
              $ref: '#/components/schemas/Role'
    PaginatedRoles:
      description: The Roles matching the query
      content:
        application/json:
          schema:
            type: object
            properties:
              data:
                type: array
                items:
                  $ref: '#/components/schemas/Role'
              pagination:
                $ref: '#/components/schemas/Pagination'
    Extranet:
      description: The matching Extranet
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Extranet'
    Extranets:
      description: The Extranets
      content:
        application/json:
          schema:
            type: array
            items:
              $ref: '#/components/schemas/Extranet'
    PaginatedExtranets:
      description: The Extranets matching the query
      content:
        application/json:
          schema:
            type: object
            properties:
              data:
                type: array
                items:
                  $ref: '#/components/schemas/Extranet'
              pagination:
                $ref: '#/components/schemas/Pagination'

    Deleted:
      description: The resource was deleted successfully

  # Object types
  schemas:
    User:
      type: object
      description: User object
      required:
        - username
        - firstname
        - surname
        - email
      properties:
        id:
          type: integer
          description: User ID
          example: 335
          readOnly: true
        blocked:
          type: boolean
          description: Whether the user is blocked
          example: false
        username:
          type: string
          description: Username
          example: jsmith
        firstname:
          type: string
          description: First name
          example: Jane
        surname:
          type: string
          description: Surname
          example: Smith
        fullname:
          type: string
          description: Firstname and surname
          example: Jane Smith
          readOnly: true
        email:
          type: string
          description: Email address
          example: jane.smith@consulting.co.uk
        password:
          type: string
          nullable: true
          description: Local user password
          example: correcthorsebatterystaple
          writeOnly: true
        password_reset:
          type: boolean
          description: Whether the user will need to reset their password on next login
          example: false
        company:
          type: string
          description: Company name
          example: Jane Smith Consulting Ltd
        job_title:
          type: string
          description: Job title
          example: Managing Director
        last_time_login:
          type: string
          description: Last time the user logged in
          format: date-time
          readOnly: true
        last_time_used:
          type: string
          description: Last time the user used the system
          format: date-time
          readOnly: true
        user_code:
          type: string
          example: example_user_code
        language:
          $ref: '#/components/schemas/LanguageCode'
        external_directory_id:
          type: integer
          description: External Directory ID
          example: null
          nullable: true
        external_directory_user_id:
          type: integer
          description: User ID in the External Directory
          example: null
          nullable: true
        extranet_id:
          type: integer
          description: Extranet ID
          example: 1
        extranet:
          allOf:
            - $ref: '#/components/schemas/Extranet'
            - readOnly: true
            - nullable: true
        metadata:
          type: object
          additionalProperties: true
          example:
            usr_city: Brighton
            usr_address: null
            usr_phone: "012345678900"
            usr_mobile: "012345678900"
            usr_career: null
            usr_dob: 19700101
        photo_url:
          type: string
          description: User photo URL
          example: https://yourintranet.com/appdata/people/355.jpg
          readOnly: true
          nullable: true
        # manager_url:
        #   type: string
        #   format: url
        #   example: https://yourintranet.com/api/people/v2/users/{manager_id}
        #   readOnly: true
        #   nullable: true
        subordinates_url:
          type: string
          description: API URL for the User's subordinates
          format: url
          example: https://yourintranet.com/api/people/v2/users/335/subordinates
          readOnly: true
          nullable: true
        extranet_url:
          type: string
          description: API URL for the Extranet that the User belongs to
          format: url
          example: https://yourintranet.com/api/people/v2/extranet/1
          readOnly: true
          nullable: true
        groups_url:
          type: string
          description: API URL for the Groups that the User belongs to
          format: url
          example: https://yourintranet.com/api/people/v2/users/335/groups
          readOnly: true
          nullable: true
        roles_url:
          type: string
          description: API URL for the Roles that the User belongs to
          format: url
          example: https://yourintranet.com/api/people/v2/users/335/roles
          readOnly: true
          nullable: true
    Group:
      type: object
      required:
        - name
      properties:
        id:
          type: integer
          description: Group ID
          example: 1
          readOnly: true
        name:
          type: string
          description: Group name
          example: Product Team
        description:
          type: string
          example: Product designers, developers, maintainers and managers
        inactive:
          type: boolean
          description: Whether the Group is inactive
          example: false
        parent_id:
          type: integer
          description: Parent group ID
          example: 0
        owner_id:
          type: integer
          description: Group owner ID
          example: 1
        extranet_id:
          type: integer
          description: Extranet ID
          example: 0
        extranet:
          allOf:
            - $ref: '#/components/schemas/Extranet'
            - readOnly: true
        parent_url:
          type: string
          description: API URL for the Group's parent Group
          example: https://yourintranet.com/api/people/v2/groups/{parent_id}
          readOnly: true
          nullable: true
        owner_url:
          type: string
          description: API URL for the Group's owner User
          example: https://yourintranet.com/api/people/v2/users/{owner_id}
          readOnly: true
          nullable: true
        extranet_url:
          type: string
          description: API URL for the Group's Extranet
          example: https://yourintranet.com/api/people/v2/extranets/{extranet_id}
          readOnly: true
          nullable: true
        users_url:
          type: string
          description: API URL for the Group's users
          example: https://yourintranet.com/api/people/v2/groups/1/users
          readOnly: true
          nullable: true
        subgroups_url:
          type: string
          description: API URL for the Group's subgroups
          example: https://yourintranet.com/api/people/v2/groups/1/subgroups
          readOnly: true
          nullable: true
    Role:
      type: object
      required:
        - name
      properties:
        id:
          type: integer
          description: Role ID
          example: 1
          readOnly: true
        name:
          type: string
          description: Role name
          example: Software Engineer
        description:
          type: string
          description: Role description
          example: Software developers and maintainers
        inactive:
          type: boolean
          description: Whether the Role is inactive
          example: false
        date_created:
          type: string
          description: The date the Role was created
          format: date-time
          readOnly: true
        owner_id:
          type: integer
          description: User ID of the Role's owner
          example: 1
        extranet_id:
          type: integer
          description: Extranet ID that the Role belongs to
          example: 1
        extranet:
          allOf:
            - $ref: '#/components/schemas/Extranet'
            - readOnly: true
        users_url:
          type: string
          description: API URL for the Role's Users
          example: https://yourintranet.com/api/people/v2/roles/1/users
          readOnly: true
          nullable: true
        owner_url:
          type: string
          description: API URL for the Role's owner
          example: https://yourintranet.com/api/people/v2/users/1
          readOnly: true
          nullable: true
        extranet_url:
          type: string
          description: API URL for Role's Extranet
          example: https://yourintranet.com/api/people/v2/extranets/1
          readOnly: true
          nullable: true
    Extranet:
      type: object
      required:
        - name
      properties:
        id:
          type: integer
          description: Extranet ID
          example: 1
          readOnly: true
        name:
          type: string
          description: Extranet name
          example: Primary Area (Intranet)
        description:
          type: string
          description: Extranet description
          example: ""
        primary:
          type: boolean
          description: Whether this is the Primary Extranet
          example: true
          readOnly: true
        read_only:
          type: boolean
          description: Whether this Extranet is read-only
          example: false
        admin_id:
          type: integer
          description: User ID of the Extranet's administrator
          example: 1
        logo_url:
          type: string
          description: URL of the Extranet's logo image
          example: https://yourintranet.com/appdata/logos/1.jpg
          readOnly: true
          nullable: true
        admin_url:
          type: string
          description: API URL for the Extranet's administrator
          example: https://yourintranet.com/api/people/v2/users/1
          readOnly: true
        groups_url:
          type: string
          description: API URL for the Groups that belong to the Extranet
          readOnly: true
        roles_url:
          type: string
          description: API URL for the Roles that belong to the Extranet
          readOnly: true
        users_url:
          type: string
          description: API URL for the Users that belong to the Extranet
          readOnly: true
    Contact:
      type: object
      required:
        - emailad
      properties:
        id:
          type: integer
          description: Contact ID
          readOnly: true
        firstname:
          type: string
          description: Contact first name
        surname:
          type: string
          description: Contact surname
        company:
          type: string
          description: Contact company name
        work_location:
          type: string
          description: Contact work location
        city:
          type: string
          description: Contact city name
        landline:
          type: string
          description: Landline phone number
        emailad:
          type: string
          description: Email address
        country_mobile:
          type: string
          description: Mobile phone number country code
        mobile:
          type: string
          description: Mobile phone number
          nullable: true
        pref_contact:
          type: string
          description: Preferred contact method
          nullable: true
        usercomments:
          type: string
          description: Comments from the User that owns this contact
          nullable: true
        owner:
          type: integer
          description: User ID of the Contact's owner
          nullable: true
        title:
          type: string
          description: Contact title
          nullable: true
        contact_type:
          type: integer
    SimpleContact:
      type: object
      required:
        - emailad
      properties:
        id:
          type: integer
          description: Contact ID
          example: 10
          readOnly: true
        firstname:
          type: string
          description: Contact first name
          example: Jane
        surname:
          type: string
          description: Contact surname
          example: Smith
        emailad:
          type: string
          description: Contact email address. Must be unique amongst your personal contacts.
          example: jane.smith@consulting.co.uk

    # Common schemas
    LanguageCode:
      type: string
      pattern: '^[a-z]{2}$'
      example: en
    Pagination:
      type: object
      properties:
        offset:
          type: integer
          description: The number of items results are offset by
          example: 0
          readOnly: true
        limit:
          type: integer
          description: The number of items returned
          example: 20
          readOnly: true
        total:
          type: integer
          description: The total number of items
          example: 100
          readOnly: true
        prev:
          type: string
          nullable: true
          description: URL to the previous page of items
          example: null
          readOnly: true
        next:
          type: string
          nullable: true
          description: URL to the next page of items
          example: null
          readOnly: true

  securitySchemes:
    HttpBasic:
      type: http
      scheme: basic
