openapi: 3.0.1
info:
  title: Secfix Public API
  description: "Read and manage your Secfix compliance data from your own systems.\
    \ Get an access token from `POST /oauth/token` with the OAuth 2.0 client credentials\
    \ grant, then send it as a bearer token to the `/v1` endpoints. Errors are JSON\
    \ objects with a stable `code` and the `requestId`. Lists use cursor pagination."
  contact:
    name: Secfix Support
    url: https://secfix.com
    email: support@secfix.com
  license:
    name: Proprietary
    url: https://secfix.com/license
  version: 1.0.0
servers:
- url: https://api.secfix.com
  description: Production
- url: https://api-staging.secfix.com
  description: Staging
security:
- bearerAuth: []
tags:
- name: Employees
  description: "Read the people in your workspace, with their employment status, group\
    \ and onboarding progress."
- name: Inventory
  description: "Read assets in every inventory category. Create, update and delete\
    \ `CUSTOM` and `INFORMATION` assets."
- name: OAuth
  description: Get an access token with the OAuth 2.0 client credentials grant.
- name: Groups
  description: "Read employee groups, their member counts and the onboarding tasks\
    \ assigned to them."
- name: Health
  description: Check that the API is up.
- name: Computers
  description: Read the computers in your workspace and their security settings.
paths:
  /oauth/token:
    post:
      tags:
      - OAuth
      summary: Get an access token
      description: Exchanges your API key's `client_id` and `client_secret` for a
        bearer access token (OAuth 2.0 client credentials grant). Send the body as
        `application/x-www-form-urlencoded` with `grant_type=client_credentials`.
      operationId: token
      requestBody:
        content:
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/OAuthTokenRequest'
        required: true
      responses:
        "200":
          description: Access token issued.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AccessTokenResponse'
        "400":
          description: "`grant_type` isn't `client_credentials`, or the requested\
            \ audience isn't supported. Code: `unsupported_grant_type` or `unsupported_audience`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "401":
          description: "The `client_id` and `client_secret` don't match an API key.\
            \ Code: `invalid_client`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "405":
          description: "This path doesn't support the HTTP method. The `Allow` header\
            \ lists the methods it supports. Code: `method_not_allowed`."
          headers:
            Allow:
              description: Comma-separated list of the HTTP methods this path supports.
              style: simple
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "429":
          description: "Too many token requests from this client or IP address. Wait\
            \ the number of seconds in `Retry-After`, then retry. Code: `rate_limited`."
          headers:
            Retry-After:
              description: Seconds to wait before retrying.
              style: simple
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
      security: []
  /v1/computers:
    get:
      tags:
      - Computers
      summary: List computers
      description: "Returns the computers in your workspace. `isMonitored` tells you\
        \ whether the Secfix agent reports each one. To get one employee's computers,\
        \ pass `ownerId`. Requires the `all:read` scope."
      operationId: list_2
      parameters:
      - name: pageSize
        in: query
        description: "Results per page, 1-100. Defaults to 25."
        required: false
        schema:
          type: integer
          format: int32
      - name: pageCursor
        in: query
        description: The `startCursor` or `endCursor` from a previous page of this
          list. Send the same filters as on that page. Leave it out for the first
          page.
        required: false
        schema:
          type: string
      - name: ownerId
        in: query
        description: "Return only the computers of this employee: one employee `id`,\
          \ as returned in `ownerId`. A terminated employee's computers keep their\
          \ `ownerId`, so they still match, although the Secfix app shows them as\
          \ unassigned. The owner can be someone `GET /v1/employees` doesn't list,\
          \ such as a service account or a person excluded from compliance."
        required: false
        schema:
          type: string
          format: uuid
      responses:
        "200":
          description: Computers returned.
          headers:
            X-RateLimit-Limit:
              description: Requests allowed in the current rate-limit window.
              style: simple
              schema:
                type: integer
            X-RateLimit-Remaining:
              description: Requests remaining in the current rate-limit window.
              style: simple
              schema:
                type: integer
            X-RateLimit-Reset:
              description: Seconds until the rate-limit window resets.
              style: simple
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CursorPageComputerDto'
        "401":
          description: "The access token is missing, invalid or replaced by a newer\
            \ one. Code: `unauthorized` or `token_superseded`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "403":
          description: "The access token doesn't have the scope this endpoint needs.\
            \ Code: `scope_required`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "405":
          description: "This path doesn't support the HTTP method. The `Allow` header\
            \ lists the methods it supports. Code: `method_not_allowed`."
          headers:
            Allow:
              description: Comma-separated list of the HTTP methods this path supports.
              style: simple
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "429":
          description: "Too many requests. Wait the number of seconds in `Retry-After`,\
            \ then retry. Code: `rate_limited`."
          headers:
            Retry-After:
              description: Seconds to wait before retrying.
              style: simple
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "500":
          description: "Unexpected server error. Code: `internal_error`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
  /v1/computers/{id}:
    get:
      tags:
      - Computers
      summary: Get a computer
      description: Requires the `all:read` scope.
      operationId: get_1
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      responses:
        "200":
          description: Computer returned.
          headers:
            X-RateLimit-Limit:
              description: Requests allowed in the current rate-limit window.
              style: simple
              schema:
                type: integer
            X-RateLimit-Remaining:
              description: Requests remaining in the current rate-limit window.
              style: simple
              schema:
                type: integer
            X-RateLimit-Reset:
              description: Seconds until the rate-limit window resets.
              style: simple
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ComputerDto'
        "401":
          description: "The access token is missing, invalid or replaced by a newer\
            \ one. Code: `unauthorized` or `token_superseded`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "403":
          description: "The access token doesn't have the scope this endpoint needs.\
            \ Code: `scope_required`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "404":
          description: "No computer with this `id` exists in your workspace. Code:\
            \ `not_found`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "405":
          description: "This path doesn't support the HTTP method. The `Allow` header\
            \ lists the methods it supports. Code: `method_not_allowed`."
          headers:
            Allow:
              description: Comma-separated list of the HTTP methods this path supports.
              style: simple
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "429":
          description: "Too many requests. Wait the number of seconds in `Retry-After`,\
            \ then retry. Code: `rate_limited`."
          headers:
            Retry-After:
              description: Seconds to wait before retrying.
              style: simple
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "500":
          description: "Unexpected server error. Code: `internal_error`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
  /v1/employees:
    get:
      tags:
      - Employees
      summary: List employees
      description: "Returns the people in your workspace who are included in compliance.\
        \ Only active employees are returned unless you set `status`. Service accounts\
        \ are never returned. Filters combine with AND. To pass several values to\
        \ one filter, separate them with commas: `group=Engineering,Sales`. Names\
        \ and email addresses are personal data. Requires the `all:read` scope."
      operationId: listEmployees
      parameters:
      - name: status
        in: query
        description: Employment status. Defaults to `ACTIVE`.
        required: false
        schema:
          type: string
          enum:
          - ACTIVE
          - TERMINATED
      - name: group
        in: query
        description: "Group names, comma-separated, case-insensitive. An unknown name\
          \ returns an empty page."
        required: false
        schema:
          type: string
      - name: groupId
        in: query
        description: "Group `id`s from `GET /v1/groups`, comma-separated."
        required: false
        schema:
          type: string
      - name: email
        in: query
        description: "One email address, case-insensitive."
        required: false
        schema:
          type: string
      - name: onboardingStatus
        in: query
        description: "Onboarding statuses, comma-separated: `COMPLETE`, `INCOMPLETE`,\
          \ `ONGOING` or `NOT_APPLICABLE`."
        required: false
        schema:
          type: string
      - name: pageSize
        in: query
        description: "Results per page, 1-100. Defaults to 25."
        required: false
        schema:
          type: integer
          format: int32
      - name: pageCursor
        in: query
        description: The `startCursor` or `endCursor` from a previous page of this
          list. Send the same filters as on that page. Leave it out for the first
          page.
        required: false
        schema:
          type: string
      responses:
        "200":
          description: Employees returned.
          headers:
            X-RateLimit-Limit:
              description: Requests allowed in the current rate-limit window.
              style: simple
              schema:
                type: integer
            X-RateLimit-Remaining:
              description: Requests remaining in the current rate-limit window.
              style: simple
              schema:
                type: integer
            X-RateLimit-Reset:
              description: Seconds until the rate-limit window resets.
              style: simple
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CursorPageEmployeeDto'
        "400":
          description: "A query parameter is invalid: an unknown `status` or `onboardingStatus`,\
            \ a `groupId` that isn't a UUID, a `pageSize` outside 1-100, or a `pageCursor`\
            \ that is malformed or came from a request with other filters. Code: `validation_failed`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "401":
          description: "The access token is missing, invalid or replaced by a newer\
            \ one. Code: `unauthorized` or `token_superseded`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "403":
          description: "The access token doesn't have the scope this endpoint needs.\
            \ Code: `scope_required`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "405":
          description: "This path doesn't support the HTTP method. The `Allow` header\
            \ lists the methods it supports. Code: `method_not_allowed`."
          headers:
            Allow:
              description: Comma-separated list of the HTTP methods this path supports.
              style: simple
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "429":
          description: "Too many requests. Wait the number of seconds in `Retry-After`,\
            \ then retry. Code: `rate_limited`."
          headers:
            Retry-After:
              description: Seconds to wait before retrying.
              style: simple
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "500":
          description: "Unexpected server error. Code: `internal_error`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
  /v1/employees/{id}:
    get:
      tags:
      - Employees
      summary: Get an employee
      description: "Returns active and terminated employees. An unknown `id`, an `id`\
        \ from another workspace and a service account all return 404. Requires the\
        \ `all:read` scope."
      operationId: getEmployee
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      responses:
        "200":
          description: Employee returned.
          headers:
            X-RateLimit-Limit:
              description: Requests allowed in the current rate-limit window.
              style: simple
              schema:
                type: integer
            X-RateLimit-Remaining:
              description: Requests remaining in the current rate-limit window.
              style: simple
              schema:
                type: integer
            X-RateLimit-Reset:
              description: Seconds until the rate-limit window resets.
              style: simple
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EmployeeDto'
        "401":
          description: "The access token is missing, invalid or replaced by a newer\
            \ one. Code: `unauthorized` or `token_superseded`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "403":
          description: "The access token doesn't have the scope this endpoint needs.\
            \ Code: `scope_required`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "404":
          description: "No employee with this `id` exists in your workspace. Code:\
            \ `not_found`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "405":
          description: "This path doesn't support the HTTP method. The `Allow` header\
            \ lists the methods it supports. Code: `method_not_allowed`."
          headers:
            Allow:
              description: Comma-separated list of the HTTP methods this path supports.
              style: simple
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "429":
          description: "Too many requests. Wait the number of seconds in `Retry-After`,\
            \ then retry. Code: `rate_limited`."
          headers:
            Retry-After:
              description: Seconds to wait before retrying.
              style: simple
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "500":
          description: "Unexpected server error. Code: `internal_error`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
  /v1/groups:
    get:
      tags:
      - Groups
      summary: List groups
      description: "Returns the employee groups in your workspace, oldest first. Requires\
        \ the `all:read` scope."
      operationId: listGroups
      parameters:
      - name: name
        in: query
        description: "Group names, comma-separated, case-insensitive."
        required: false
        schema:
          type: string
      - name: pageSize
        in: query
        description: "Results per page, 1-100. Defaults to 25."
        required: false
        schema:
          type: integer
          format: int32
      - name: pageCursor
        in: query
        description: The `startCursor` or `endCursor` from a previous page of this
          list. Send the same filters as on that page. Leave it out for the first
          page.
        required: false
        schema:
          type: string
      responses:
        "200":
          description: Groups returned.
          headers:
            X-RateLimit-Limit:
              description: Requests allowed in the current rate-limit window.
              style: simple
              schema:
                type: integer
            X-RateLimit-Remaining:
              description: Requests remaining in the current rate-limit window.
              style: simple
              schema:
                type: integer
            X-RateLimit-Reset:
              description: Seconds until the rate-limit window resets.
              style: simple
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CursorPageGroupDto'
        "400":
          description: "A query parameter is invalid: a `pageSize` outside 1-100,\
            \ or a `pageCursor` that is malformed or came from a request with other\
            \ filters. Code: `validation_failed`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "401":
          description: "The access token is missing, invalid or replaced by a newer\
            \ one. Code: `unauthorized` or `token_superseded`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "403":
          description: "The access token doesn't have the scope this endpoint needs.\
            \ Code: `scope_required`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "405":
          description: "This path doesn't support the HTTP method. The `Allow` header\
            \ lists the methods it supports. Code: `method_not_allowed`."
          headers:
            Allow:
              description: Comma-separated list of the HTTP methods this path supports.
              style: simple
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "429":
          description: "Too many requests. Wait the number of seconds in `Retry-After`,\
            \ then retry. Code: `rate_limited`."
          headers:
            Retry-After:
              description: Seconds to wait before retrying.
              style: simple
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "500":
          description: "Unexpected server error. Code: `internal_error`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
  /v1/groups/{id}:
    get:
      tags:
      - Groups
      summary: Get a group
      description: "Returns one group with its settings: trainings, device monitoring\
        \ and policy acceptance. Requires the `all:read` scope."
      operationId: getGroup
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      responses:
        "200":
          description: Group returned.
          headers:
            X-RateLimit-Limit:
              description: Requests allowed in the current rate-limit window.
              style: simple
              schema:
                type: integer
            X-RateLimit-Remaining:
              description: Requests remaining in the current rate-limit window.
              style: simple
              schema:
                type: integer
            X-RateLimit-Reset:
              description: Seconds until the rate-limit window resets.
              style: simple
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/GroupDetailDto'
        "401":
          description: "The access token is missing, invalid or replaced by a newer\
            \ one. Code: `unauthorized` or `token_superseded`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "403":
          description: "The access token doesn't have the scope this endpoint needs.\
            \ Code: `scope_required`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "404":
          description: "No group with this `id` exists in your workspace. Code: `not_found`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "405":
          description: "This path doesn't support the HTTP method. The `Allow` header\
            \ lists the methods it supports. Code: `method_not_allowed`."
          headers:
            Allow:
              description: Comma-separated list of the HTTP methods this path supports.
              style: simple
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "429":
          description: "Too many requests. Wait the number of seconds in `Retry-After`,\
            \ then retry. Code: `rate_limited`."
          headers:
            Retry-After:
              description: Seconds to wait before retrying.
              style: simple
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "500":
          description: "Unexpected server error. Code: `internal_error`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
  /v1/health:
    get:
      tags:
      - Health
      summary: Check API health
      description: Returns the service status and the API version. Doesn't need an
        access token.
      operationId: health
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HealthDto'
        "405":
          description: "This path doesn't support the HTTP method. The `Allow` header\
            \ lists the methods it supports. Code: `method_not_allowed`."
          headers:
            Allow:
              description: Comma-separated list of the HTTP methods this path supports.
              style: simple
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
      security: []
  /v1/inventory/assets:
    get:
      tags:
      - Inventory
      summary: List assets
      description: Returns assets from every inventory category. Assets hidden in
        the Secfix app and deleted assets aren't returned. Filters combine with AND.
        Requires the `all:read` scope.
      operationId: list_1
      parameters:
      - name: pageSize
        in: query
        description: "Results per page, 1-100. Defaults to 25."
        required: false
        schema:
          type: integer
          format: int32
      - name: pageCursor
        in: query
        description: The `startCursor` or `endCursor` from a previous page of this
          list. Send the same filters as on that page. Leave it out for the first
          page.
        required: false
        schema:
          type: string
      - name: categoryKey
        in: query
        description: Return only assets in this category. Leave it out for all categories.
        required: false
        schema:
          type: string
          enum:
          - CLOUD
          - COMPUTER
          - CUSTOM
          - INFORMATION
          - EMPLOYEE
      - name: subKey
        in: query
        description: "Return only assets of this sub-type, such as `CLOUD_STORAGE_BUCKET`.\
          \ It's the value an asset returns in `categoryKey`. If you also send `categoryKey`,\
          \ the sub-type must belong to it."
        required: false
        schema:
          type: string
          enum:
          - CLOUD
          - CLOUD_AUTOSCALE_GROUPS
          - CLOUD_COMPUTE_INSTANCE
          - CLOUD_CONTAINER_REPOSITORY
          - CLOUD_DATA_WAREHOUSE
          - CLOUD_LOAD_BALANCER
          - CLOUD_NO_SQL_DATABASE
          - CLOUD_PAAS_APPS
          - CLOUD_QUEUE
          - CLOUD_RELATIONAL_DATABASE
          - CLOUD_STORAGE_BUCKET
          - CLOUD_OTHER
          - COMPUTER
          - CUSTOM
          - INFORMATION
          - EMPLOYEE
      - name: hasOwner
        in: query
        description: "`true` returns assets with an owner, `false` assets without\
          \ one."
        required: false
        schema:
          type: boolean
      - name: hasDescription
        in: query
        description: "`true` returns assets with a description, `false` assets without\
          \ one."
        required: false
        schema:
          type: boolean
      - name: classification
        in: query
        description: Return only assets with this data classification.
        required: false
        schema:
          type: string
          enum:
          - RESTRICTED
          - CONFIDENTIAL
          - INTERNAL
          - PUBLIC
          - UNKNOWN
      - name: ownerStatus
        in: query
        description: "Same as `hasOwner`: `COMPLETE` returns assets with an owner,\
          \ `INCOMPLETE` assets without one."
        required: false
        schema:
          type: string
          enum:
          - COMPLETE
          - INCOMPLETE
      - name: auditStatus
        in: query
        description: "Return only assets with this audit status, as shown in the Secfix\
          \ app. `COMPLETE` means every field the category needs for an audit is set.\
          \ Assets without an audit status match neither value."
        required: false
        schema:
          type: string
          enum:
          - COMPLETE
          - INCOMPLETE
      - name: externalSource
        in: query
        description: Return only assets created through the API with this `externalSource`.
        required: false
        schema:
          type: string
      - name: externalAssetId
        in: query
        description: Return only the asset with this `externalAssetId`. Requires `externalSource`.
        required: false
        schema:
          type: string
      responses:
        "200":
          description: Assets returned.
          headers:
            X-RateLimit-Limit:
              description: Requests allowed in the current rate-limit window.
              style: simple
              schema:
                type: integer
            X-RateLimit-Remaining:
              description: Requests remaining in the current rate-limit window.
              style: simple
              schema:
                type: integer
            X-RateLimit-Reset:
              description: Seconds until the rate-limit window resets.
              style: simple
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CursorPageAssetDto'
        "401":
          description: "The access token is missing, invalid or replaced by a newer\
            \ one. Code: `unauthorized` or `token_superseded`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "403":
          description: "The access token doesn't have the scope this endpoint needs.\
            \ Code: `scope_required`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "405":
          description: "This path doesn't support the HTTP method. The `Allow` header\
            \ lists the methods it supports. Code: `method_not_allowed`."
          headers:
            Allow:
              description: Comma-separated list of the HTTP methods this path supports.
              style: simple
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "429":
          description: "Too many requests. Wait the number of seconds in `Retry-After`,\
            \ then retry. Code: `rate_limited`."
          headers:
            Retry-After:
              description: Seconds to wait before retrying.
              style: simple
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "500":
          description: "Unexpected server error. Code: `internal_error`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
    post:
      tags:
      - Inventory
      summary: Create or update an asset
      description: |-
        Creates a `CUSTOM` or `INFORMATION` asset. It appears in Secfix like an asset added in the app. Set the owner with `ownerId` or `ownerEmail`.

        To link the asset to a record in your own system, send `externalSource` and `externalAssetId`. If an asset in the same category already has that pair, the call updates it instead: only the fields you send change, and the response is 200 instead of 201.

        Requires the `all:write` scope.
      operationId: createAsset
      parameters:
      - name: Idempotency-Key
        in: header
        description: "A unique key, up to 256 characters, that makes the request safe\
          \ to retry. Use a new UUID for each distinct request. If you send the same\
          \ key again, you get the first response back, for at least 24 hours after\
          \ the first request completes. Only successful (2xx) responses are stored.\
          \ If the first request is still running, you get `409 idempotency_in_progress`:\
          \ wait the number of seconds in `Retry-After`, then retry. See [Idempotency](/idempotency)."
        required: true
        schema:
          maxLength: 256
          type: string
          example: b0f8e5a2-3c1d-4e6f-8a9b-0c1d2e3f4a5b
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AssetCreateRequest'
        required: true
      responses:
        "200":
          description: An asset with the same `externalSource` and `externalAssetId`
            already existed and was updated.
          headers:
            X-RateLimit-Limit:
              description: Requests allowed in the current rate-limit window.
              style: simple
              schema:
                type: integer
            X-RateLimit-Remaining:
              description: Requests remaining in the current rate-limit window.
              style: simple
              schema:
                type: integer
            X-RateLimit-Reset:
              description: Seconds until the rate-limit window resets.
              style: simple
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AssetDto'
        "201":
          description: Asset created.
          headers:
            X-RateLimit-Limit:
              description: Requests allowed in the current rate-limit window.
              style: simple
              schema:
                type: integer
            X-RateLimit-Remaining:
              description: Requests remaining in the current rate-limit window.
              style: simple
              schema:
                type: integer
            X-RateLimit-Reset:
              description: Seconds until the rate-limit window resets.
              style: simple
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AssetDto'
        "400":
          description: "The request body is invalid, or the `Idempotency-Key` header\
            \ is missing or longer than 256 characters. Code: `validation_failed`\
            \ or `malformed_request`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "401":
          description: "The access token is missing, invalid or replaced by a newer\
            \ one. Code: `unauthorized` or `token_superseded`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "403":
          description: "The access token doesn't have the scope this endpoint needs,\
            \ or the category can't be created through the API. Code: `scope_required`\
            \ or `resource_not_writable`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "405":
          description: "This path doesn't support the HTTP method. The `Allow` header\
            \ lists the methods it supports. Code: `method_not_allowed`."
          headers:
            Allow:
              description: Comma-separated list of the HTTP methods this path supports.
              style: simple
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "409":
          description: "The `Idempotency-Key` was already used with a different body\
            \ (`idempotency_conflict`), the first request with this key is still running\
            \ (`idempotency_in_progress`), or another request created an asset with\
            \ the same `externalSource` and `externalAssetId` at the same moment (`write_conflict`).\
            \ For `idempotency_in_progress` and `write_conflict`, retry after `Retry-After`."
          headers:
            Retry-After:
              description: Seconds to wait before retrying. Sent with `idempotency_in_progress`
                and `write_conflict`.
              style: simple
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "413":
          description: "The request body is too large. Code: `payload_too_large`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "415":
          description: "Send the request body as `application/json`. Code: `unsupported_media_type`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "429":
          description: "Too many requests. Wait the number of seconds in `Retry-After`,\
            \ then retry. Code: `rate_limited`."
          headers:
            Retry-After:
              description: Seconds to wait before retrying.
              style: simple
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "500":
          description: "Unexpected server error. Code: `internal_error`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
  /v1/inventory/assets/batch-create:
    post:
      tags:
      - Inventory
      summary: Create assets in a batch
      description: |-
        Creates up to 100 `CUSTOM` or `INFORMATION` assets in one request. Each record is validated and saved on its own, so one invalid record doesn't stop the others. The response is 200 with one result per record, in request order.

        A record whose `externalSource` and `externalAssetId` match an existing asset in its category updates that asset instead: its `action` is `UPDATED`, and only the fields you send change. So you can resend the same list without creating duplicates. If the same pair appears twice in one request, the whole request is rejected.

        A batch counts as one write request for rate limiting. Requires the `all:write` scope.
      operationId: createAssetsBatch
      parameters:
      - name: Idempotency-Key
        in: header
        description: "A unique key, up to 256 characters, that makes the request safe\
          \ to retry. Use a new UUID for each distinct request. If you send the same\
          \ key again, you get the first response back, for at least 24 hours after\
          \ the first request completes. Only successful (2xx) responses are stored.\
          \ If the first request is still running, you get `409 idempotency_in_progress`:\
          \ wait the number of seconds in `Retry-After`, then retry. See [Idempotency](/idempotency)."
        required: true
        schema:
          maxLength: 256
          type: string
          example: b0f8e5a2-3c1d-4e6f-8a9b-0c1d2e3f4a5b
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BatchAssetCreateRequest'
        required: true
      responses:
        "200":
          description: "Every record was processed. Check `status` on each entry in\
            \ `results`; each entry has the record's `index`. Resend only the failed\
            \ records, with a new `Idempotency-Key`."
          headers:
            X-RateLimit-Limit:
              description: Requests allowed in the current rate-limit window.
              style: simple
              schema:
                type: integer
            X-RateLimit-Remaining:
              description: Requests remaining in the current rate-limit window.
              style: simple
              schema:
                type: integer
            X-RateLimit-Reset:
              description: Seconds until the rate-limit window resets.
              style: simple
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BatchResponse'
        "400":
          description: "The request is invalid: `records` is missing, empty or has\
            \ more than 100 entries, the same `categoryKey`, `externalSource` and\
            \ `externalAssetId` appear twice, or the `Idempotency-Key` header is missing\
            \ or longer than 256 characters. Code: `validation_failed` or `malformed_request`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "401":
          description: "The access token is missing, invalid or replaced by a newer\
            \ one. Code: `unauthorized` or `token_superseded`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "403":
          description: "The access token doesn't have the scope this endpoint needs.\
            \ Code: `scope_required`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "405":
          description: "This path doesn't support the HTTP method. The `Allow` header\
            \ lists the methods it supports. Code: `method_not_allowed`."
          headers:
            Allow:
              description: Comma-separated list of the HTTP methods this path supports.
              style: simple
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "409":
          description: "The `Idempotency-Key` was already used with a different body\
            \ (`idempotency_conflict`), or the first request with this key is still\
            \ running (`idempotency_in_progress`). For `idempotency_in_progress`,\
            \ retry after `Retry-After`."
          headers:
            Retry-After:
              description: "Seconds to wait before retrying. Sent with `idempotency_in_progress`.\
                \ A `write_conflict` on one record is reported in that record's result,\
                \ not as a 409."
              style: simple
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "413":
          description: "The request body is too large. Code: `payload_too_large`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "415":
          description: "Send the request body as `application/json`. Code: `unsupported_media_type`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "429":
          description: "Too many requests. Wait the number of seconds in `Retry-After`,\
            \ then retry. Code: `rate_limited`."
          headers:
            Retry-After:
              description: Seconds to wait before retrying.
              style: simple
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "500":
          description: "Unexpected server error. Code: `internal_error`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
  /v1/inventory/assets/batch-delete:
    post:
      tags:
      - Inventory
      summary: Delete assets in a batch
      description: Deletes up to 100 `CUSTOM` or `INFORMATION` assets in one request.
        Each record is processed on its own. An unknown or already deleted `id` fails
        with `not_found` in its result. Each `id` can appear only once. A batch counts
        as one write request for rate limiting. Requires the `all:write` scope.
      operationId: deleteAssetsBatch
      parameters:
      - name: Idempotency-Key
        in: header
        description: "A unique key, up to 256 characters, that makes the request safe\
          \ to retry. Use a new UUID for each distinct request. If you send the same\
          \ key again, you get the first response back, for at least 24 hours after\
          \ the first request completes. Only successful (2xx) responses are stored.\
          \ If the first request is still running, you get `409 idempotency_in_progress`:\
          \ wait the number of seconds in `Retry-After`, then retry. See [Idempotency](/idempotency)."
        required: true
        schema:
          maxLength: 256
          type: string
          example: b0f8e5a2-3c1d-4e6f-8a9b-0c1d2e3f4a5b
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BatchAssetDeleteRequest'
        required: true
      responses:
        "200":
          description: "Every record was processed. Check `status` on each entry in\
            \ `results`; each entry has the record's `index`. Resend only the failed\
            \ records, with a new `Idempotency-Key`."
          headers:
            X-RateLimit-Limit:
              description: Requests allowed in the current rate-limit window.
              style: simple
              schema:
                type: integer
            X-RateLimit-Remaining:
              description: Requests remaining in the current rate-limit window.
              style: simple
              schema:
                type: integer
            X-RateLimit-Reset:
              description: Seconds until the rate-limit window resets.
              style: simple
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BatchResponse'
        "400":
          description: "The request is invalid: `records` is missing, empty or has\
            \ more than 100 entries, an `id` appears twice, or the `Idempotency-Key`\
            \ header is missing or longer than 256 characters. Code: `validation_failed`\
            \ or `malformed_request`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "401":
          description: "The access token is missing, invalid or replaced by a newer\
            \ one. Code: `unauthorized` or `token_superseded`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "403":
          description: "The access token doesn't have the scope this endpoint needs.\
            \ Code: `scope_required`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "405":
          description: "This path doesn't support the HTTP method. The `Allow` header\
            \ lists the methods it supports. Code: `method_not_allowed`."
          headers:
            Allow:
              description: Comma-separated list of the HTTP methods this path supports.
              style: simple
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "409":
          description: "The `Idempotency-Key` was already used with a different body\
            \ (`idempotency_conflict`), or the first request with this key is still\
            \ running (`idempotency_in_progress`). For `idempotency_in_progress`,\
            \ retry after `Retry-After`."
          headers:
            Retry-After:
              description: "Seconds to wait before retrying. Sent with `idempotency_in_progress`.\
                \ A `write_conflict` on one record is reported in that record's result,\
                \ not as a 409."
              style: simple
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "413":
          description: "The request body is too large. Code: `payload_too_large`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "415":
          description: "Send the request body as `application/json`. Code: `unsupported_media_type`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "429":
          description: "Too many requests. Wait the number of seconds in `Retry-After`,\
            \ then retry. Code: `rate_limited`."
          headers:
            Retry-After:
              description: Seconds to wait before retrying.
              style: simple
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "500":
          description: "Unexpected server error. Code: `internal_error`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
  /v1/inventory/assets/batch-update:
    patch:
      tags:
      - Inventory
      summary: Update assets in a batch
      description: |-
        Updates up to 100 `CUSTOM` or `INFORMATION` assets in one request, each with its own values. Each record is saved on its own, so one invalid record doesn't stop the others. The response is 200 with one result per record, in request order. An unknown `id` fails with `not_found`. Any other asset (a computer, cloud resource or employee) fails with `resource_not_writable`.

        Records follow the bulk edit rules of the Secfix app. Some fields can't be bulk-edited in some categories: the field isn't configured for the category, a Secfix tag sets it, or it's marked not editable. This can include `classification`. Such a field is skipped and listed in `skippedFields`, and the other fields are saved, so the record is still `SUCCESS`. If every change in a record is skipped, nothing is saved and the record fails with `not_editable`. The single-asset `PATCH` rejects such a field with `validation_failed` instead.

        `tags` aren't supported in a batch; use the single-asset `PATCH`. Each `id` can appear only once. A batch counts as one write request for rate limiting. Requires the `all:write` scope.
      operationId: updateAssetsBatch
      parameters:
      - name: Idempotency-Key
        in: header
        description: "A unique key, up to 256 characters, that makes the request safe\
          \ to retry. Use a new UUID for each distinct request. If you send the same\
          \ key again, you get the first response back, for at least 24 hours after\
          \ the first request completes. Only successful (2xx) responses are stored.\
          \ If the first request is still running, you get `409 idempotency_in_progress`:\
          \ wait the number of seconds in `Retry-After`, then retry. See [Idempotency](/idempotency)."
        required: true
        schema:
          maxLength: 256
          type: string
          example: b0f8e5a2-3c1d-4e6f-8a9b-0c1d2e3f4a5b
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BatchAssetUpdateRequest'
        required: true
      responses:
        "200":
          description: "Every record was processed. Check `status` on each entry in\
            \ `results`; each entry has the record's `index`. Resend only the failed\
            \ records, with a new `Idempotency-Key`."
          headers:
            X-RateLimit-Limit:
              description: Requests allowed in the current rate-limit window.
              style: simple
              schema:
                type: integer
            X-RateLimit-Remaining:
              description: Requests remaining in the current rate-limit window.
              style: simple
              schema:
                type: integer
            X-RateLimit-Reset:
              description: Seconds until the rate-limit window resets.
              style: simple
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BatchResponse'
        "400":
          description: "The request is invalid: `records` is missing, empty or has\
            \ more than 100 entries, an `id` appears twice, or the `Idempotency-Key`\
            \ header is missing or longer than 256 characters. Code: `validation_failed`\
            \ or `malformed_request`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "401":
          description: "The access token is missing, invalid or replaced by a newer\
            \ one. Code: `unauthorized` or `token_superseded`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "403":
          description: "The access token doesn't have the scope this endpoint needs.\
            \ Code: `scope_required`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "405":
          description: "This path doesn't support the HTTP method. The `Allow` header\
            \ lists the methods it supports. Code: `method_not_allowed`."
          headers:
            Allow:
              description: Comma-separated list of the HTTP methods this path supports.
              style: simple
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "409":
          description: "The `Idempotency-Key` was already used with a different body\
            \ (`idempotency_conflict`), or the first request with this key is still\
            \ running (`idempotency_in_progress`). For `idempotency_in_progress`,\
            \ retry after `Retry-After`."
          headers:
            Retry-After:
              description: "Seconds to wait before retrying. Sent with `idempotency_in_progress`.\
                \ A `write_conflict` on one record is reported in that record's result,\
                \ not as a 409."
              style: simple
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "413":
          description: "The request body is too large. Code: `payload_too_large`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "415":
          description: "Send the request body as `application/json`. Code: `unsupported_media_type`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "429":
          description: "Too many requests. Wait the number of seconds in `Retry-After`,\
            \ then retry. Code: `rate_limited`."
          headers:
            Retry-After:
              description: Seconds to wait before retrying.
              style: simple
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "500":
          description: "Unexpected server error. Code: `internal_error`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
  /v1/inventory/assets/{id}:
    get:
      tags:
      - Inventory
      summary: Get an asset
      description: Requires the `all:read` scope.
      operationId: get
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      responses:
        "200":
          description: Asset returned.
          headers:
            X-RateLimit-Limit:
              description: Requests allowed in the current rate-limit window.
              style: simple
              schema:
                type: integer
            X-RateLimit-Remaining:
              description: Requests remaining in the current rate-limit window.
              style: simple
              schema:
                type: integer
            X-RateLimit-Reset:
              description: Seconds until the rate-limit window resets.
              style: simple
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AssetDto'
        "401":
          description: "The access token is missing, invalid or replaced by a newer\
            \ one. Code: `unauthorized` or `token_superseded`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "403":
          description: "The access token doesn't have the scope this endpoint needs.\
            \ Code: `scope_required`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "404":
          description: "No asset with this `id` exists in your workspace. Code: `not_found`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "405":
          description: "This path doesn't support the HTTP method. The `Allow` header\
            \ lists the methods it supports. Code: `method_not_allowed`."
          headers:
            Allow:
              description: Comma-separated list of the HTTP methods this path supports.
              style: simple
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "429":
          description: "Too many requests. Wait the number of seconds in `Retry-After`,\
            \ then retry. Code: `rate_limited`."
          headers:
            Retry-After:
              description: Seconds to wait before retrying.
              style: simple
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "500":
          description: "Unexpected server error. Code: `internal_error`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
    delete:
      tags:
      - Inventory
      summary: Delete an asset
      description: Deletes a `CUSTOM` or `INFORMATION` asset. Deleting an asset that's
        already deleted returns 404. Requires the `all:write` scope.
      operationId: deleteAsset
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      responses:
        "204":
          description: Asset deleted.
          headers:
            X-RateLimit-Limit:
              description: Requests allowed in the current rate-limit window.
              style: simple
              schema:
                type: integer
            X-RateLimit-Remaining:
              description: Requests remaining in the current rate-limit window.
              style: simple
              schema:
                type: integer
            X-RateLimit-Reset:
              description: Seconds until the rate-limit window resets.
              style: simple
              schema:
                type: integer
        "401":
          description: "The access token is missing, invalid or replaced by a newer\
            \ one. Code: `unauthorized` or `token_superseded`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "403":
          description: "The access token doesn't have the scope this endpoint needs,\
            \ or the asset can't be deleted through the API. Code: `scope_required`\
            \ or `resource_not_writable`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "404":
          description: "No asset with this `id` exists in your workspace. Code: `not_found`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "405":
          description: "This path doesn't support the HTTP method. The `Allow` header\
            \ lists the methods it supports. Code: `method_not_allowed`."
          headers:
            Allow:
              description: Comma-separated list of the HTTP methods this path supports.
              style: simple
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "409":
          description: "Another write to this asset is in progress. Retry after `Retry-After`.\
            \ Code: `write_conflict`."
          headers:
            Retry-After:
              description: Seconds to wait before retrying.
              style: simple
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "429":
          description: "Too many requests. Wait the number of seconds in `Retry-After`,\
            \ then retry. Code: `rate_limited`."
          headers:
            Retry-After:
              description: Seconds to wait before retrying.
              style: simple
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "500":
          description: "Unexpected server error. Code: `internal_error`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
    patch:
      tags:
      - Inventory
      summary: Update an asset
      description: "Updates a `CUSTOM` or `INFORMATION` asset: `name`, `customIdentifier`,\
        \ owner, `description`, `classification`, `dataStored` and `tags`. Only the\
        \ fields you send change. Other assets (computers, cloud resources and employees)\
        \ are read-only through the API and return 403 `resource_not_writable`. Requires\
        \ the `all:write` scope."
      operationId: update
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      - name: Idempotency-Key
        in: header
        description: "A unique key, up to 256 characters, that makes the request safe\
          \ to retry. Use a new UUID for each distinct request. If you send the same\
          \ key again, you get the first response back, for at least 24 hours after\
          \ the first request completes. Only successful (2xx) responses are stored.\
          \ If the first request is still running, you get `409 idempotency_in_progress`:\
          \ wait the number of seconds in `Retry-After`, then retry. See [Idempotency](/idempotency)."
        required: true
        schema:
          maxLength: 256
          type: string
          example: b0f8e5a2-3c1d-4e6f-8a9b-0c1d2e3f4a5b
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AssetUpdateRequest'
        required: true
      responses:
        "200":
          description: Asset updated.
          headers:
            X-RateLimit-Limit:
              description: Requests allowed in the current rate-limit window.
              style: simple
              schema:
                type: integer
            X-RateLimit-Remaining:
              description: Requests remaining in the current rate-limit window.
              style: simple
              schema:
                type: integer
            X-RateLimit-Reset:
              description: Seconds until the rate-limit window resets.
              style: simple
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AssetDto'
        "400":
          description: "The request body is invalid, or the `Idempotency-Key` header\
            \ is missing or longer than 256 characters. Code: `validation_failed`\
            \ or `malformed_request`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "401":
          description: "The access token is missing, invalid or replaced by a newer\
            \ one. Code: `unauthorized` or `token_superseded`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "403":
          description: "The access token doesn't have the scope this endpoint needs,\
            \ or the asset isn't `CUSTOM` or `INFORMATION`, so it can't be changed\
            \ through the API. Code: `scope_required` or `resource_not_writable`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "404":
          description: "No asset with this `id` exists in your workspace. Code: `not_found`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "405":
          description: "This path doesn't support the HTTP method. The `Allow` header\
            \ lists the methods it supports. Code: `method_not_allowed`."
          headers:
            Allow:
              description: Comma-separated list of the HTTP methods this path supports.
              style: simple
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "409":
          description: "The `Idempotency-Key` was already used with a different body\
            \ (`idempotency_conflict`), the first request with this key is still running\
            \ (`idempotency_in_progress`), or another write to this asset is in progress\
            \ (`write_conflict`). For `idempotency_in_progress` and `write_conflict`,\
            \ retry after `Retry-After`."
          headers:
            Retry-After:
              description: Seconds to wait before retrying. Sent with `idempotency_in_progress`
                and `write_conflict`.
              style: simple
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "413":
          description: "The request body is too large. Code: `payload_too_large`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "415":
          description: "Send the request body as `application/json`. Code: `unsupported_media_type`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "429":
          description: "Too many requests. Wait the number of seconds in `Retry-After`,\
            \ then retry. Code: `rate_limited`."
          headers:
            Retry-After:
              description: Seconds to wait before retrying.
              style: simple
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "500":
          description: "Unexpected server error. Code: `internal_error`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
  /v1/inventory/categories:
    get:
      tags:
      - Inventory
      summary: List asset categories
      description: Returns the inventory categories and their keys. Requires the `all:read`
        scope.
      operationId: list
      parameters:
      - name: pageSize
        in: query
        description: "Results per page, 1-100. Defaults to 25."
        required: false
        schema:
          type: integer
          format: int32
      - name: pageCursor
        in: query
        description: The `startCursor` or `endCursor` from a previous page of this
          list. Send the same filters as on that page. Leave it out for the first
          page.
        required: false
        schema:
          type: string
      responses:
        "200":
          description: Asset categories returned.
          headers:
            X-RateLimit-Limit:
              description: Requests allowed in the current rate-limit window.
              style: simple
              schema:
                type: integer
            X-RateLimit-Remaining:
              description: Requests remaining in the current rate-limit window.
              style: simple
              schema:
                type: integer
            X-RateLimit-Reset:
              description: Seconds until the rate-limit window resets.
              style: simple
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CursorPageAssetCategoryDto'
        "401":
          description: "The access token is missing, invalid or replaced by a newer\
            \ one. Code: `unauthorized` or `token_superseded`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "403":
          description: "The access token doesn't have the scope this endpoint needs.\
            \ Code: `scope_required`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "405":
          description: "This path doesn't support the HTTP method. The `Allow` header\
            \ lists the methods it supports. Code: `method_not_allowed`."
          headers:
            Allow:
              description: Comma-separated list of the HTTP methods this path supports.
              style: simple
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "429":
          description: "Too many requests. Wait the number of seconds in `Retry-After`,\
            \ then retry. Code: `rate_limited`."
          headers:
            Retry-After:
              description: Seconds to wait before retrying.
              style: simple
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
        "500":
          description: "Unexpected server error. Code: `internal_error`."
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
components:
  schemas:
    AccessTokenResponse:
      type: object
      properties:
        access_token:
          type: string
          description: "The bearer access token, a JWT signed with RS256."
          example: eyJhbGciOiJSUzI1NiIsImtpZCI6...
        expires_in:
          type: integer
          description: Seconds until the token expires.
          format: int64
          example: 86400
        token_type:
          type: string
          description: Always `Bearer`.
          example: Bearer
      description: Access token response.
    AssetCategoryDto:
      type: object
      properties:
        displayLabel:
          type: string
          description: Category name as shown in Secfix.
          example: Cloud
        key:
          type: string
          description: Category key. It doesn't change.
          example: CLOUD
      description: An inventory category.
    AssetCreateRequest:
      required:
      - categoryKey
      - name
      type: object
      properties:
        categoryKey:
          type: string
          description: "Category to create the asset in: `CUSTOM` or `INFORMATION`,\
            \ in any letter case."
          example: CUSTOM
          enum:
          - CUSTOM
          - INFORMATION
        classification:
          type: string
          description: "Data classification, in any letter case. Defaults to `INTERNAL`."
          example: CONFIDENTIAL
          enum:
          - RESTRICTED
          - CONFIDENTIAL
          - INTERNAL
          - PUBLIC
          - UNKNOWN
        customIdentifier:
          maxLength: 255
          minLength: 0
          type: string
          description: "Serial number or asset ID, shown in Secfix as **ID/Serial\
            \ No.** Up to 255 characters. Free text and not unique: to identify the\
            \ asset in your system, use `externalSource` and `externalAssetId`."
          example: SN-48213
        dataStored:
          $ref: '#/components/schemas/DataStoredInput'
        description:
          maxLength: 500
          minLength: 0
          type: string
          description: "Asset description, up to 500 characters."
          example: Printer in the front office.
        externalAssetId:
          maxLength: 255
          minLength: 0
          type: string
          description: "The asset's id in your system. Up to 255 characters; leading\
            \ and trailing spaces are removed. Must be unique per workspace, category\
            \ and `externalSource` among assets that haven't been deleted. Matched\
            \ exactly. Send it with `externalSource`. You can't change it later."
          example: CI-1042
        externalSource:
          maxLength: 255
          minLength: 0
          type: string
          description: "A name you choose for the system the asset comes from, such\
            \ as `servicenow`. Up to 255 characters; leading and trailing spaces are\
            \ removed. Matched exactly, so send the same value every time. Send it\
            \ with `externalAssetId`."
          example: servicenow-cmdb
        name:
          maxLength: 255
          minLength: 0
          type: string
          description: "Asset name, 1-255 characters. Leading and trailing spaces\
            \ are removed."
          example: Office badge printer
        ownerEmail:
          maxLength: 320
          minLength: 0
          type: string
          description: "Owner's email address, case-insensitive. Send `ownerId` or\
            \ `ownerEmail`, not both."
          example: alex@example.com
        ownerId:
          type: string
          description: "Owner's employee `id`. Send `ownerId` or `ownerEmail`, not\
            \ both. An asset without an owner shows as incomplete."
          format: uuid
          example: a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d
      description: "Creates one `CUSTOM` or `INFORMATION` asset. It appears in Secfix\
        \ like an asset added in the app. Send `externalSource` and `externalAssetId`\
        \ to link it to a record in your system: a later create with the same pair\
        \ in the same category updates this asset instead of adding another, and changes\
        \ only the fields you send."
    AssetDto:
      type: object
      properties:
        accountId:
          type: string
          description: Cloud account id. `CLOUD` assets only.
          example: "123456789012"
        auditStatus:
          type: string
          description: "Audit status, as shown in the Secfix app: `COMPLETE` when\
            \ every field the category needs for an audit is set, otherwise `INCOMPLETE`.\
            \ Left out when Secfix hasn't computed it yet. Read-only."
          readOnly: true
          example: INCOMPLETE
          enum:
          - COMPLETE
          - INCOMPLETE
        categoryKey:
          type: string
          description: "The asset's category key. For cloud assets it's the sub-type,\
            \ such as `CLOUD_QUEUE`."
          example: CLOUD
          enum:
          - CLOUD
          - COMPUTER
          - CUSTOM
          - INFORMATION
          - EMPLOYEE
        classification:
          type: string
          description: Data classification.
          example: CONFIDENTIAL
        createdAt:
          type: string
          description: When the asset was created (UTC).
          format: date-time
          example: 2026-01-15T09:30:00Z
        customIdentifier:
          type: string
          description: "Serial number or asset ID, shown in Secfix as **ID/Serial\
            \ No.**: the provider's resource id for cloud assets, the serial number\
            \ for computers, and free text for `CUSTOM` and `INFORMATION` assets.\
            \ Not unique."
          example: i-0abc123def456
        dataStored:
          $ref: '#/components/schemas/DataStoredDto'
        description:
          type: string
          description: Asset description.
          example: Primary production web server.
        email:
          type: string
          description: Employee's email address. Personal data. `EMPLOYEE` assets
            only.
          example: jane.doe@example.com
        externalAssetId:
          type: string
          description: "The asset's id in your system, as sent on create. Left out\
            \ for other assets."
          example: CI-1042
        externalSource:
          type: string
          description: "The system the asset comes from, as sent on create. Only set\
            \ on `CUSTOM` and `INFORMATION` assets created through the API."
          example: servicenow-cmdb
        id:
          type: string
          description: The asset's id (UUID).
          format: uuid
          example: 3f1c9a2e-8b4d-4e7a-9c1f-2a5b6c7d8e9f
        lastCheckedAt:
          type: string
          description: When the asset was last checked for compliance (UTC). Left
            out for assets that aren't checked.
          format: date-time
          example: 2026-06-30T02:00:00Z
        name:
          type: string
          description: Asset name.
          example: prod-web-01
        osVersion:
          type: string
          description: Operating system and version. `COMPUTER` assets only.
          example: macOS 14.5
        ownerId:
          type: string
          description: "Owner's employee `id`: the owner the Secfix app shows. The\
            \ owner can be someone `GET /v1/employees` doesn't list, such as a service\
            \ account or a person excluded from compliance, so looking them up there\
            \ can return 404."
          format: uuid
          example: a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d
        ownerSource:
          type: string
          description: Where the owner assignment comes from.
          example: MANUAL
        ownerStatus:
          type: string
          description: "`COMPLETE` when the asset has an owner, otherwise `INCOMPLETE`.\
            \ Set for every category. This isn't the audit status; see `auditStatus`.\
            \ Read-only."
          readOnly: true
          example: COMPLETE
          enum:
          - COMPLETE
          - INCOMPLETE
        region:
          type: string
          description: Cloud region or location. `CLOUD` assets only.
          example: eu-central-1
        serialNumber:
          type: string
          description: Hardware serial number. `COMPUTER` assets only.
          example: C02XY1234ABC
        tags:
          type: array
          description: Tags on the asset.
          items:
            $ref: '#/components/schemas/TagDto'
        type:
          type: string
          description: Asset type within its category.
          example: SERVER
      description: "An inventory asset. Fields marked with a category are only set\
        \ for assets in that category. For `EMPLOYEE` assets, `id` is the employee's\
        \ `id`."
    AssetUpdateRequest:
      type: object
      properties:
        classification:
          type: string
          description: "Data classification: `RESTRICTED`, `CONFIDENTIAL`, `INTERNAL`,\
            \ `PUBLIC` or `UNKNOWN`, in any letter case."
          example: CONFIDENTIAL
        customIdentifier:
          maxLength: 255
          minLength: 0
          type: string
          description: "Serial number or asset ID, shown in Secfix as **ID/Serial\
            \ No.** Up to 255 characters. You can't change `externalSource` or `externalAssetId`;\
            \ they're set on create."
          example: SN-12345
        dataStored:
          $ref: '#/components/schemas/DataStoredInput'
        description:
          maxLength: 500
          minLength: 0
          type: string
          description: "Asset description, up to 500 characters."
          example: Primary production web server.
        name:
          maxLength: 255
          minLength: 0
          type: string
          description: "New asset name, 1-255 characters. Leading and trailing spaces\
            \ are removed, and a blank name is rejected."
          example: Finance laptop pool
        ownerEmail:
          maxLength: 320
          minLength: 0
          type: string
          description: "New owner's email address, instead of `ownerId`. Case-insensitive.\
            \ Must belong to an active employee in your workspace who is included\
            \ in compliance."
          example: jane.doe@example.com
        ownerId:
          type: string
          description: New owner's employee `id`.
          format: uuid
          example: a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d
        tags:
          maxItems: 20
          minItems: 0
          type: array
          description: "Your workspace's tags to set on the asset. Tags you leave\
            \ out are removed. Each `key` must be a tag key that exists in your workspace;\
            \ an unknown key is rejected. Tags managed by Secfix are read-only and\
            \ stay as they are, so you don't need to send them. Single-asset `PATCH`\
            \ only; not supported in a batch."
          items:
            $ref: '#/components/schemas/TagDto'
      description: "Updates a `CUSTOM` or `INFORMATION` asset. Only the fields you\
        \ send change. A field set by a Secfix tag on the asset (an owner, description\
        \ or data-stored flag) can't be changed; the update is rejected with `validation_failed`\
        \ on that field."
    BatchAssetCreateRequest:
      required:
      - records
      type: object
      properties:
        records:
          maxItems: 100
          minItems: 1
          type: array
          description: "The assets to create, 1-100. Each has the same fields as a\
            \ single create."
          items:
            $ref: '#/components/schemas/AssetCreateRequest'
      description: Creates up to 100 `CUSTOM` or `INFORMATION` assets. Each record
        is validated on its own.
    BatchAssetDeleteRecord:
      required:
      - id
      type: object
      properties:
        id:
          type: string
          description: The `id` of the asset to delete.
          format: uuid
          example: 3f1c9a2e-8b4d-4e7a-9c1f-2a5b6c7d8e9f
      description: One asset to delete.
    BatchAssetDeleteRequest:
      required:
      - records
      type: object
      properties:
        records:
          maxItems: 100
          minItems: 1
          type: array
          description: "The assets to delete, 1-100. Each `id` can appear only once."
          items:
            $ref: '#/components/schemas/BatchAssetDeleteRecord'
      description: Deletes up to 100 `CUSTOM` or `INFORMATION` assets.
    BatchAssetUpdateRecord:
      required:
      - id
      type: object
      properties:
        classification:
          type: string
          description: "Data classification: `RESTRICTED`, `CONFIDENTIAL`, `INTERNAL`,\
            \ `PUBLIC` or `UNKNOWN`, in any letter case."
          example: CONFIDENTIAL
        customIdentifier:
          maxLength: 255
          minLength: 0
          type: string
          description: "Serial number or asset ID, shown in Secfix as **ID/Serial\
            \ No.** Up to 255 characters. You can't change `externalSource` or `externalAssetId`;\
            \ they're set on create."
          example: SN-12345
        dataStored:
          $ref: '#/components/schemas/DataStoredInput'
        description:
          maxLength: 500
          minLength: 0
          type: string
          description: "Asset description, up to 500 characters."
          example: Primary production web server.
        id:
          type: string
          description: The `id` of the asset to update.
          format: uuid
          example: 3f1c9a2e-8b4d-4e7a-9c1f-2a5b6c7d8e9f
        name:
          maxLength: 255
          minLength: 0
          type: string
          description: "New asset name, 1-255 characters. Leading and trailing spaces\
            \ are removed, and a blank name is rejected."
          example: Finance laptop pool
        ownerEmail:
          maxLength: 320
          minLength: 0
          type: string
          description: "New owner's email address, instead of `ownerId`. Case-insensitive.\
            \ Must belong to an active employee in your workspace who is included\
            \ in compliance."
          example: jane.doe@example.com
        ownerId:
          type: string
          description: New owner's employee `id`.
          format: uuid
          example: a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d
        tags:
          maxItems: 20
          minItems: 0
          type: array
          description: "Your workspace's tags to set on the asset. Tags you leave\
            \ out are removed. Each `key` must be a tag key that exists in your workspace;\
            \ an unknown key is rejected. Tags managed by Secfix are read-only and\
            \ stay as they are, so you don't need to send them. Single-asset `PATCH`\
            \ only; not supported in a batch."
          items:
            $ref: '#/components/schemas/TagDto'
      description: "One asset to update: its `id` and the fields to change. Only `CUSTOM`\
        \ and `INFORMATION` assets can be updated. `tags` aren't supported in a batch."
    BatchAssetUpdateRequest:
      required:
      - records
      type: object
      properties:
        records:
          maxItems: 100
          minItems: 1
          type: array
          description: "The assets to update, 1-100. Each `id` can appear only once."
          items:
            $ref: '#/components/schemas/BatchAssetUpdateRecord'
      description: "Updates up to 100 `CUSTOM` or `INFORMATION` assets, each with\
        \ its own values. `tags` are only supported by the single-asset `PATCH`."
    BatchItemResult:
      type: object
      properties:
        action:
          type: string
          description: "For a successful create: whether the asset was created or\
            \ updated."
          enum:
          - CREATED
          - UPDATED
        code:
          type: string
          description: Why the record failed. Only set when it failed.
          example: validation_failed
          enum:
          - validation_failed
          - resource_not_writable
          - not_editable
          - not_found
          - write_conflict
          - internal_error
        field:
          type: string
          description: The request field that failed validation. Only set for `validation_failed`.
          example: ownerEmail
        id:
          type: string
          description: "For a create, the `id` of the new or matched asset; left out\
            \ when the create failed. For a delete or update, the `id` you sent."
          format: uuid
        index:
          type: integer
          description: "Position of the record in `records`, starting at 0."
          format: int32
          example: 0
        message:
          type: string
          description: Short explanation of the failure. Only set when the record
            failed.
          example: unknown owner
        skippedFields:
          type: array
          description: "Batch updates only. Fields you sent that weren't changed,\
            \ because the asset's category doesn't allow bulk editing them: the field\
            \ isn't configured, a Secfix tag sets it, or it's marked not editable.\
            \ On a `SUCCESS` record the other fields were saved; on a `not_editable`\
            \ record nothing was. Left out when every change was applied."
          items:
            type: string
            example: description
        status:
          type: string
          description: Outcome of the record.
          enum:
          - SUCCESS
          - ERROR
      description: The result of one record in a batch.
    BatchResponse:
      type: object
      properties:
        results:
          type: array
          description: "One result per record, in request order."
          items:
            $ref: '#/components/schemas/BatchItemResult'
      description: "Results of a batch request, one per record. The response is 200\
        \ even when some or all records failed. Resend only the failed records, with\
        \ a new `Idempotency-Key`."
    CategorySummaryDto:
      type: object
      properties:
        completed:
          type: integer
          description: Number of tasks in this category the employee has completed.
          format: int32
          example: 1
        status:
          type: string
          description: Onboarding status of this category's tasks.
          example: ONGOING
          enum:
          - COMPLETE
          - INCOMPLETE
          - ONGOING
          - NOT_APPLICABLE
        total:
          type: integer
          description: "Number of tasks in this category that apply to the employee:\
            \ not marked N/A, and enabled for your workspace's frameworks."
          format: int32
          example: 2
      description: Onboarding progress in one task category.
    CompliancePostureDto:
      type: object
      properties:
        agentVersion:
          type: string
          description: Version of the Secfix agent. Left out when no agent is installed.
          example: 3.4.1
        antivirusInstalled:
          type: boolean
          description: Whether antivirus is installed.
          example: true
        diskEncryptionEnabled:
          type: boolean
          description: Whether disk encryption is enabled.
          example: true
        passwordManagerInstalled:
          type: boolean
          description: Whether a password manager is installed.
          example: false
        screenLockEnabled:
          type: boolean
          description: Whether screen lock is enabled.
          example: true
      description: "Security settings of the computer: disk encryption, antivirus,\
        \ screen lock, password manager and agent version."
    ComputerDto:
      type: object
      properties:
        compliance:
          $ref: '#/components/schemas/CompliancePostureDto'
        id:
          type: string
          description: The computer's id (UUID).
          format: uuid
          example: 7c2d1e3f-4a5b-4c6d-8e9f-0a1b2c3d4e5f
        isMonitored:
          type: boolean
          description: Whether the Secfix agent reports this computer.
          example: true
        lastCheckedAt:
          type: string
          description: When the computer last checked in (UTC).
          format: date-time
          example: 2026-06-30T02:00:00Z
        name:
          type: string
          description: Computer name or hostname.
          example: MacBook-Pro-Jane
        operatingSystem:
          type: string
          description: Operating system.
          example: macOS
        osVersion:
          type: string
          description: Operating system version.
          example: "14.5"
        ownerId:
          type: string
          description: "Owner's employee `id`: the owner the Secfix app shows. The\
            \ owner can be someone `GET /v1/employees` doesn't list, such as a service\
            \ account or a person excluded from compliance, so looking them up there\
            \ can return 404."
          format: uuid
          example: a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d
        serialNumber:
          type: string
          description: Hardware serial number.
          example: C02XG2JMJGH7
        tags:
          type: array
          description: Tags on the computer.
          items:
            $ref: '#/components/schemas/TagDto'
      description: "A computer in your workspace, with its security settings. Read-only."
    CursorPageAssetCategoryDto:
      type: object
      properties:
        pageInfo:
          $ref: '#/components/schemas/PageInfo'
        results:
          type: array
          description: The results on this page.
          items:
            $ref: '#/components/schemas/AssetCategoryDto'
      description: A page of results.
    CursorPageAssetDto:
      type: object
      properties:
        pageInfo:
          $ref: '#/components/schemas/PageInfo'
        results:
          type: array
          description: The results on this page.
          items:
            $ref: '#/components/schemas/AssetDto'
      description: A page of results.
    CursorPageComputerDto:
      type: object
      properties:
        pageInfo:
          $ref: '#/components/schemas/PageInfo'
        results:
          type: array
          description: The results on this page.
          items:
            $ref: '#/components/schemas/ComputerDto'
      description: A page of results.
    CursorPageEmployeeDto:
      type: object
      properties:
        pageInfo:
          $ref: '#/components/schemas/PageInfo'
        results:
          type: array
          description: The results on this page.
          items:
            $ref: '#/components/schemas/EmployeeDto'
      description: A page of results.
    CursorPageGroupDto:
      type: object
      properties:
        pageInfo:
          $ref: '#/components/schemas/PageInfo'
        results:
          type: array
          description: The results on this page.
          items:
            $ref: '#/components/schemas/GroupDto'
      description: A page of results.
    DataStoredDto:
      type: object
      properties:
        containsPatientData:
          type: boolean
          description: Whether the asset contains patient data.
          example: false
        containsUserData:
          type: boolean
          description: Whether the asset contains user data.
          example: true
        userDataInfo:
          type: string
          description: What kind of user data the asset contains.
          example: Customer contact records
      description: What data a `CUSTOM` or `INFORMATION` asset stores. Set it with
        `dataStored` on create or update.
    DataStoredInput:
      type: object
      properties:
        containsPatientData:
          type: boolean
          description: Whether the asset stores patient data.
          example: false
        containsUserData:
          type: boolean
          description: Whether the asset stores user data.
          example: true
        userDataInfo:
          maxLength: 500
          minLength: 0
          type: string
          description: "What kind of user data the asset stores, up to 500 characters."
          example: Customer names and email addresses.
      description: "What data the asset stores. On create, fields you leave out stay\
        \ unset."
    EmployeeDto:
      type: object
      properties:
        email:
          type: string
          description: Email address.
          example: alice@example.com
        endContractDate:
          type: string
          description: Contract end date. Left out when unknown.
          format: date
          example: 2026-12-31
        groupId:
          type: string
          description: The `id` of the employee's group (see `GET /v1/groups`). Left
            out when the employee has no group.
          format: uuid
          example: 9b2d4f6a-1c3e-4a5b-8d7f-0e1a2b3c4d5e
        groupName:
          type: string
          description: Name of the employee's group. Left out when the employee has
            no group.
          example: Engineering
        id:
          type: string
          description: The employee's id (UUID).
          format: uuid
          example: 3f1c9a2e-94b1-4d72-a7d8-123456789abc
        name:
          type: string
          description: Full name.
          example: Alice Doe
        onboardingStatus:
          type: string
          description: "Onboarding status, computed from the employee's tasks in this\
            \ workspace the same way as on the **People** page in Secfix. `NOT_APPLICABLE`\
            \ for a terminated employee or one with no applicable tasks. If the employee\
            \ belongs to more than one workspace, the **People** page currently also\
            \ counts tasks from the other workspaces, so the two can differ."
          example: ONGOING
          enum:
          - COMPLETE
          - INCOMPLETE
          - ONGOING
          - NOT_APPLICABLE
        source:
          type: string
          description: Where the record comes from.
          example: GOOGLE_WORKSPACE
          enum:
          - GOOGLE_WORKSPACE
          - MANUAL
          - MS_OFFICE365
          - RETOOL
          - HRIS
        startContractDate:
          type: string
          description: Contract start date. Left out when unknown.
          format: date
          example: 2025-01-15
        status:
          type: string
          description: Employment status. `TERMINATED` once the employee is archived
            or deleted in Secfix.
          example: ACTIVE
          enum:
          - ACTIVE
          - TERMINATED
        tasksSummary:
          $ref: '#/components/schemas/TasksSummaryDto'
      description: A person in your workspace and their onboarding progress.
    EmployeeTaskDto:
      type: object
      properties:
        category:
          type: string
          description: Task category.
          example: TRAINING
          enum:
          - MONITORING
          - TRAINING
          - POLICIES
        completedAt:
          type: string
          description: When the task was completed. Left out if it hasn't been.
          format: date-time
          example: 2026-03-02T09:15:00Z
        expiresAt:
          type: string
          description: "When the completed task expires, for recurring trainings.\
            \ Left out if it doesn't expire."
          format: date-time
          example: 2027-03-02T00:00:00Z
        key:
          type: string
          description: "Task key, such as `SECURITY_AWARENESS_TRAINING`, `POLICIES_ACCEPTANCE`\
            \ or `SECFIX_AGENT`. New keys can be added, so handle keys you don't know."
          example: SECURITY_AWARENESS_TRAINING
        name:
          type: string
          description: Task name as shown in Secfix.
          example: Security awareness training
        status:
          type: string
          description: "Task status, as shown on the employee's page in Secfix. An\
            \ expired task is `INCOMPLETE`. A hidden task is `NOT_APPLICABLE`, and\
            \ so is every task of an active employee whose onboarding is `NOT_APPLICABLE`.\
            \ A terminated employee's tasks keep their real status."
          example: COMPLETE
          enum:
          - COMPLETE
          - INCOMPLETE
          - NOT_APPLICABLE
      description: "One onboarding task of the employee, as listed on their page in\
        \ Secfix."
    GroupDetailDto:
      type: object
      properties:
        createdAt:
          type: string
          description: When the group was created. Left out for older groups created
            before Secfix recorded this.
          format: date-time
          example: 2026-02-11T10:20:30Z
        deviceMonitoring:
          $ref: '#/components/schemas/GroupDeviceMonitoringDto'
        employeeCount:
          type: integer
          description: Number of active employees in the group who are included in
            compliance. Matches the count on the **Groups** page in Secfix.
          format: int32
          example: 12
        id:
          type: string
          description: The group's id (UUID).
          format: uuid
          example: 9b2d4f6a-1c3e-4a5b-8d7f-0e1a2b3c4d5e
        isDefault:
          type: boolean
          description: "Whether this is the workspace's default group, which new employees\
            \ join."
          example: false
        memberType:
          type: string
          description: Who the group holds. Left out when not set; such a group has
            no members counted.
          example: PEOPLE
          enum:
          - PEOPLE
          - SERVICE_ACCOUNTS
        name:
          type: string
          description: Group name.
          example: Engineering
        policyAcceptance:
          $ref: '#/components/schemas/GroupPolicyAcceptanceDto'
        tasks:
          type: array
          description: "The onboarding tasks assigned to the group, the same as `tasks`\
            \ in the group list."
          items:
            $ref: '#/components/schemas/TaskRefDto'
        trainings:
          type: array
          description: "Every training enabled for your workspace's frameworks, in\
            \ the order Secfix shows them, and whether each one is assigned to this\
            \ group."
          items:
            $ref: '#/components/schemas/GroupTrainingDto'
      description: "A group and its settings: trainings, device monitoring and policy\
        \ acceptance."
    GroupDeviceMonitoringDto:
      type: object
      properties:
        enabled:
          type: boolean
          description: Whether device monitoring is assigned to this group.
          example: true
        subTasks:
          type: array
          description: "The device monitoring steps, in the order Secfix shows them."
          items:
            $ref: '#/components/schemas/GroupSubTaskDto'
      description: Device monitoring settings of the group.
    GroupDto:
      type: object
      properties:
        createdAt:
          type: string
          description: When the group was created. Left out for older groups created
            before Secfix recorded this.
          format: date-time
          example: 2026-02-11T10:20:30Z
        employeeCount:
          type: integer
          description: Number of active employees in the group who are included in
            compliance. Matches the count on the **Groups** page in Secfix.
          format: int32
          example: 12
        id:
          type: string
          description: The group's id (UUID).
          format: uuid
          example: 9b2d4f6a-1c3e-4a5b-8d7f-0e1a2b3c4d5e
        isDefault:
          type: boolean
          description: "Whether this is the workspace's default group, which new employees\
            \ join."
          example: false
        memberType:
          type: string
          description: Who the group holds. Left out when not set; such a group has
            no members counted.
          example: PEOPLE
          enum:
          - PEOPLE
          - SERVICE_ACCOUNTS
        name:
          type: string
          description: Group name.
          example: Engineering
        tasks:
          type: array
          description: "The onboarding tasks assigned to the group, as the **Groups**\
            \ page in Secfix shows them: tasks enabled for your workspace's frameworks\
            \ and, for policy acceptance, with at least one policy assigned. Trainings\
            \ come first, then device monitoring, then policies."
          items:
            $ref: '#/components/schemas/TaskRefDto'
      description: A group of employees and the onboarding tasks assigned to it.
    GroupPolicyAcceptanceDto:
      type: object
      properties:
        enabled:
          type: boolean
          description: Whether policy acceptance is assigned to this group.
          example: true
        policies:
          type: array
          description: "The approved policies assigned to the group, sorted by name,\
            \ with custom policies after the others."
          items:
            $ref: '#/components/schemas/PolicyRefDto'
      description: Policy acceptance settings of the group.
    GroupSubTaskDto:
      type: object
      properties:
        enabled:
          type: boolean
          description: Whether the step is assigned to this group. Steps other than
            MDM show as unassigned while device monitoring itself isn't assigned.
          example: true
        key:
          type: string
          description: Task key.
          example: SECFIX_AGENT
        name:
          type: string
          description: Step name.
          example: Install the Secfix agent
      description: "A device monitoring step, such as installing the Secfix agent\
        \ or setting up MDM."
    GroupTrainingDto:
      type: object
      properties:
        description:
          type: string
          description: Training description. Left out when there is none.
        enabled:
          type: boolean
          description: Whether the training is assigned to this group.
          example: true
        key:
          type: string
          description: Task key.
          example: SECURITY_AWARENESS_TRAINING
        name:
          type: string
          description: Training name.
          example: Security awareness training
      description: A training your workspace can assign to groups.
    HealthDto:
      type: object
      properties:
        status:
          type: string
          description: Always `ok` while the API is serving requests.
          example: ok
        version:
          type: string
          description: API version.
          example: 1.0.0
      description: API health status.
    OAuthTokenRequest:
      required:
      - client_id
      - client_secret
      - grant_type
      type: object
      properties:
        client_id:
          type: string
          description: Your API key's client id.
          example: aB3xY7...
        client_secret:
          type: string
          description: Your API key's client secret.
          example: s3cr3t...
        grant_type:
          type: string
          description: OAuth 2.0 grant type. Use `client_credentials`.
          example: client_credentials
          enum:
          - client_credentials
      description: "Token request, sent as `application/x-www-form-urlencoded`."
    PageInfo:
      type: object
      properties:
        endCursor:
          type: string
          description: "Cursor for the next page. Send it as `pageCursor`, with the\
            \ same filters. Left out when there is no next page."
          example: AgAAAAX0bYb1Q0AAJDNmMWM5YTJlLTk0YjEtNGQ3Mi1hN2Q4LTEyMzQ1Njc4OWFiYw
        hasNextPage:
          type: boolean
          description: Whether there is a next page.
          example: true
        hasPreviousPage:
          type: boolean
          description: Whether there is a previous page.
          example: false
        pageCount:
          type: integer
          description: Number of results on this page.
          format: int32
          example: 25
        startCursor:
          type: string
          description: "Cursor for the previous page. Send it as `pageCursor`, with\
            \ the same filters. Left out when the page is empty and there is no previous\
            \ page."
          example: AgEAAAX0bYb1Q0AAJDNmMWM5YTJlLTk0YjEtNGQ3Mi1hN2Q4LTEyMzQ1Njc4OWFiYw
        totalCount:
          type: integer
          description: "Number of results that match your filters across all pages,\
            \ at the time of the call. It doesn't depend on `pageCursor` or `pageSize`,\
            \ and it changes when results are added or removed between calls."
          format: int64
          example: 312
      description: Pagination details.
    PolicyRefDto:
      type: object
      properties:
        id:
          type: string
          description: The policy's id.
          format: uuid
          example: 5e8f0a1b-2c3d-4e5f-9a6b-7c8d9e0f1a2b
        name:
          type: string
          description: Policy name.
          example: Acceptable Use Policy
      description: An approved policy the group's members must accept.
    ProblemDetail:
      type: object
      properties:
        code:
          type: string
          description: Error code for your error handling. It doesn't change between
            releases.
          example: not_found
        detail:
          type: string
          description: What went wrong in this request.
          example: No asset found for the given id.
        instance:
          type: string
          description: URI that identifies this occurrence of the error.
          example: /v1/inventory/assets/3f1c9a2e-8b4d-4e7a-9c1f-2a5b6c7d8e9f
        requestId:
          type: string
          description: "The request's id, also sent in the `X-Request-Id` header.\
            \ Include it when you contact support."
          example: req_01HZY8Q3M4N5P6R7S8T9V0W1X2
        status:
          type: integer
          description: HTTP status code.
          format: int32
          example: 404
        title:
          type: string
          description: Short summary of the error type.
          example: Not Found
        type:
          type: string
          description: URI that identifies the error type.
          example: https://api.secfix.com/problems/not_found
      description: The JSON body of every error response.
    TagDto:
      type: object
      properties:
        key:
          maxLength: 1000
          minLength: 0
          type: string
          description: "Tag key. On writes, it must be a tag key that exists in your\
            \ workspace."
          example: environment
        readOnly:
          type: boolean
          description: "`true` for tags managed by Secfix, such as `SecfixOwner`.\
            \ You can't change those through the API. Ignored on writes."
          readOnly: true
          example: false
        value:
          maxLength: 255
          minLength: 0
          type: string
          description: Tag value.
          example: production
      description: "A tag on an asset. On writes, `key` must be a tag key in your\
        \ workspace that you can edit."
    TaskRefDto:
      type: object
      properties:
        category:
          type: string
          description: Task category.
          example: TRAINING
          enum:
          - MONITORING
          - TRAINING
          - POLICIES
        key:
          type: string
          description: "Task key. New keys can be added, so handle keys you don't\
            \ know."
          example: SECURITY_AWARENESS_TRAINING
        name:
          type: string
          description: Task name as shown in Secfix.
          example: Security awareness training
      description: An onboarding task assigned to the group's members.
    TasksSummaryDto:
      type: object
      properties:
        deviceMonitoring:
          $ref: '#/components/schemas/CategorySummaryDto'
        policyAcceptance:
          $ref: '#/components/schemas/CategorySummaryDto'
        tasks:
          type: array
          description: "The tasks that can be assigned to the employee and are enabled\
            \ for your workspace's frameworks, in the order Secfix shows them."
          items:
            $ref: '#/components/schemas/EmployeeTaskDto'
        trainings:
          $ref: '#/components/schemas/CategorySummaryDto'
      description: "Onboarding progress by task category, and the employee's tasks."
  securitySchemes:
    bearerAuth:
      type: http
      description: Access token from `POST /oauth/token`.
      scheme: bearer
      bearerFormat: JWT
    oauth2ClientCredentials:
      type: oauth2
      description: OAuth 2.0 client credentials grant through `POST /oauth/token`.
      flows:
        clientCredentials:
          tokenUrl: /oauth/token
          scopes:
            all:read: Read access to every resource.
            all:write: Write access to every resource.
