{
  "openapi" : "3.1.0",
  "info" : {
    "title" : "Forward Networks: NQE API",
    "description" : "Ask the Network Query Engine for structured, vendor-agnostic network information",
    "contact" : {
      "email" : "support@forwardnetworks.com"
    },
    "license" : {
      "name" : "MIT",
      "url" : "https://spdx.org/licenses/MIT"
    },
    "version" : "${apiVersion}"
  },
  "servers" : [
    {
      "url" : "/"
    }
  ],
  "tags" : [
    {
      "name" : "NQE",
      "description" : "Nqe Controller"
    }
  ],
  "paths" : {
    "/api/nqe" : {
      "post" : {
        "tags" : [
          "NQE"
        ],
        "summary" : "Runs an NQE query on a Snapshot.",
        "operationId" : "runNqeQueryUsingPOST",
        "parameters" : [
          {
            "name" : "networkId",
            "in" : "query",
            "description" : "The ID of the Network to query. Required unless the `snapshotId` parameter is provided.",
            "required" : false,
            "allowEmptyValue" : false,
            "style" : "form",
            "explode" : true,
            "schema" : {
              "type" : "string"
            }
          },
          {
            "name" : "snapshotId",
            "in" : "query",
            "description" : "An optional Snapshot id. If omitted, the network’s latest processed Snapshot is used.",
            "required" : false,
            "allowEmptyValue" : false,
            "style" : "form",
            "explode" : true,
            "schema" : {
              "type" : "string"
            }
          }
        ],
        "requestBody" : {
          "description" : "Each property in the example request body is explained here. To see a detailed explanation of all properties allowed in the request body, switch from the \"Example Value\" tab to the \"Schema\" tab.\n\n- The `query` property contains query source code. Use this to run a query directly.\n- The `queryId` property contains the Query ID of a committed query in NQE Library. Use `queryId` to run a query identified by its Query ID.\n- The `commitId` property contains a Commit ID of the query identified by the `queryId` property. Use `commitId` to run a specific version of a committed query.\n- The `queryOptions` property contains refinements of the result set and/or specifies the JSON format.\n    - The `offset` property specifies the starting row to include in the response. For example, an offset of 200 would return rows starting from the 200th row. If not specified, an `offset` of 0 will be used.\n    - The `limit` property specifies the maximum number of rows to include in the response. For example, a limit of 1,000 indicates that up to 1,000 rows starting from the given offset should be included in the response. If not set, a `limit` of 1,000 will be used. The maximum value for `limit` is 10,000.\n    - The `sortBy` property specifies which column to sort by. It can be omitted.\n    - The `columnFilters` property specifies a collection of conditions on column values. The response will only include rows satisfying all specified column filters.\n    - In the sample below, up to 100 rows are requested, starting from row 20, from the result set consisting of all the rows, sorted by the \"deviceName\" column in ascending order and limited to those rows whose \"deviceName\" field contains \"ATL\", rendered with JSON arrays and objects instead of strings.\n- The `parameters` property contains a JSON object providing the values for the parameters to use while executing the query for this request. The provided parameter values must match the parameter types declared in the NQE query. This property can be omitted or the empty object if the query has no declared parameters.\n    - In the sample below, values for \"mtuThreshold\" and \"ntpServers\" are specified. The query must define parameters \"mtuThreshold\" of type `Integer` and \"ntpServers\" of type `List<IpAddress>` for these values to be valid.\n\nNote that the sample JSON object contains both the `query` and `queryId` properties and therefore is NOT a legal request. If you use this example for testing, make sure to remove one of them.\n",
          "content" : {
            "application/json" : {
              "schema" : {
                "$ref" : "#/components/schemas/NqeQueryRunRequest"
              }
            }
          },
          "required" : true
        },
        "responses" : {
          "200" : {
            "description" : "The response is an object containing two fields: a `\"snapshotId\"` field, that indicates the Snapshot that the query was run against, and an `\"items\"` field, that contains the query's results.\n\nThe `\"items\"` field contains an array of objects that resulted from the query. Each object in the `\"items\"` array, is either a \"basic\" value or a list of \"basic\" values, where a \"basic\" value is either a number, boolean, string, or null.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/NqeRunResult"
                }
              }
            }
          },
          "400" : {
            "description" : "The query did not complete successfully. For example, the query could not be parsed, the column filters were invalid, or the query timed out or was cancelled during execution. The response will contain `\"completionType\"`, `\"errors\"`, and `\"snapshotId\"` fields that provide detailed information onthe errors. See model for more information.\n\nNOTE: A 400 code can also be thrown for other errors, such as a lack of permission to execute the query, or a request that specified a Query ID for a deleted query without also specifying a Commit ID. In such cases, the `\"completionType\"`, `\"errors\"`, and `\"snapshotId\"` fields will be omitted from the response.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/NqeErrorInfo"
                }
              }
            }
          }
        },
        "deprecated" : false,
        "security" : [
          {
            "api_token" : [ ]
          }
        ]
      }
    },
    "/api/nqe-diffs/{before}/{after}" : {
      "post" : {
        "tags" : [
          "NQE"
        ],
        "summary" : "Diffs the results of two NQE queries between two Snapshots.",
        "operationId" : "getNqeQueryDiffUsingPOST",
        "parameters" : [
          {
            "name" : "before",
            "in" : "path",
            "description" : "The ID for the Snapshot to base the diff on.",
            "required" : true,
            "style" : "simple",
            "explode" : false,
            "schema" : {
              "type" : "string"
            }
          },
          {
            "name" : "after",
            "in" : "path",
            "description" : "The ID for the Snapshot to diff against the base Snapshot.",
            "required" : true,
            "style" : "simple",
            "explode" : false,
            "schema" : {
              "type" : "string"
            }
          }
        ],
        "requestBody" : {
          "description" : "The `queryId` property contains a Query ID of a query in NQE Library (this can be found in the information callout of a query listed in the Queries pane). The `commitId` property contains a Commit ID of the query identified by `queryId` (this can also be found in either the information callout in the Queries pane, or in the callout in the Versions view dropdown). Use `commitId` to run a specific version of the query.\n\nThe `options` property is optional and can be used to refine the result set. In the sample object below, `options` requests up to 100 rows, starting from row 20, from the result set consisting of all the rows, sorted by \"Name\" column in ascending order and limited to those rows whose \"Name\" field contains \"ATL\". The `options` property also allows for sorting and filtering on the diff change type column. To do this, set the `columnName` value on either the `sortBy` or `columnFilters` field to \"ChangeType\". It has three possible values: \"MODIFIED\", \"ADDED\", or \"DELETED\".\n\nThe `parameters` property can be omitted if the query has no declared parameters. If the query declares parameters, the `parameters` property should contain a JSON object providing the values for the parameters to use while executing the query for this request. The provided parameter values must match the parameter types declared in the NQE query.\n\n",
          "content" : {
            "application/json" : {
              "schema" : {
                "$ref" : "#/components/schemas/NqeDiffRequest"
              }
            }
          },
          "required" : true
        },
        "responses" : {
          "200" : {
            "description" : "The response is an object containing two fields: `totalNumValues`, indicating the total number of differences per row that the query has across the two given snapshots, and `rows`, containing an array of objects indicating the differences between two rows in the query result.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/NqeDiffResult"
                }
              }
            }
          },
          "400" : {
            "description" : "The diff request did not complete successfully. For example, the query indicated by `queryId` could be invalid, the `options` for the query were invalid, the query and/or diff timed out or was cancelled during execution, or the user does not have permission to execute the query.",
            "content" : { }
          }
        },
        "deprecated" : false,
        "security" : [
          {
            "api_token" : [ ]
          }
        ]
      }
    },
    "/api/nqe/queries" : {
      "get" : {
        "tags" : [
          "NQE"
        ],
        "summary" : "Lists all NQE queries",
        "operationId" : "getNqeQueriesUsingGET",
        "parameters" : [
          {
            "name" : "dir",
            "in" : "query",
            "description" : "If specified, include only queries in the given directory. The directory must start and end with a forward slash, such as `/L3/Advanced/`.",
            "required" : false,
            "allowEmptyValue" : false,
            "style" : "form",
            "explode" : true,
            "schema" : {
              "type" : "string"
            }
          }
        ],
        "responses" : {
          "200" : {
            "description" : "OK",
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "array",
                  "items" : {
                    "$ref" : "#/components/schemas/NqeQuery"
                  }
                }
              }
            }
          }
        },
        "deprecated" : false,
        "security" : [
          {
            "api_token" : [ ]
          }
        ]
      }
    }
  },
  "components" : {
    "schemas" : {
      "BetweenColumnFilter" : {
        "required" : [
          "columnName",
          "operator"
        ],
        "type" : "object",
        "properties" : {
          "columnName" : {
            "type" : "string",
            "description" : "The name of a column to filter on.",
            "examples" : [
              "Name"
            ]
          },
          "lowerBound" : {
            "type" : "string",
            "description" : "A value (in its string representation) to limit on inclusively from below. Required if 'upperBound' is omitted.",
            "examples" : [
              "2023-07-30T08:27:16Z"
            ]
          },
          "operator" : {
            "type" : "string",
            "enum" : [
              "IS_BETWEEN"
            ]
          },
          "upperBound" : {
            "type" : "string",
            "description" : "A value (in its string representation) to limit on inclusively from above. Required if 'lowerBound' is omitted.",
            "examples" : [
              "2025-07-30T08:27:16Z"
            ]
          }
        }
      },
      "CellValue" : {
        "type" : "object"
      },
      "ColumnFilter" : {
        "required" : [
          "operator"
        ],
        "type" : "object",
        "properties" : {
          "operator" : {
            "type" : "string",
            "enum" : [
              "DEFAULT",
              "IS_BETWEEN"
            ]
          }
        },
        "discriminator" : {
          "propertyName" : "operator",
          "mapping" : {
            "DEFAULT" : "#/components/schemas/DefaultColumnFilter",
            "IS_BETWEEN" : "#/components/schemas/BetweenColumnFilter"
          }
        }
      },
      "DefaultColumnFilter" : {
        "required" : [
          "columnName"
        ],
        "type" : "object",
        "properties" : {
          "columnName" : {
            "type" : "string",
            "description" : "The name of a column to filter on.",
            "examples" : [
              "Name"
            ]
          },
          "operator" : {
            "type" : "string",
            "enum" : [
              "DEFAULT"
            ]
          },
          "value" : {
            "type" : "string",
            "description" : "A value (in its string representation) to match on.",
            "examples" : [
              "ATL"
            ]
          }
        }
      },
      "NqeDiffEntry" : {
        "type" : "object",
        "properties" : {
          "after" : {
            "$ref" : "#/components/schemas/NqeRecord",
            "description" : "The record returned by the query against the 'after' snapshot. Not present if `type` is \"DELETED\"."
          },
          "before" : {
            "$ref" : "#/components/schemas/NqeRecord",
            "description" : "The record returned by the query against the 'before' snapshot. Not present if `type` is \"ADDED\"."
          },
          "type" : {
            "type" : "string",
            "description" : "Describes the type of difference between `before` and `after`:\n* If \"MODIFIED\", then both `before` and `after` will be present, but will differ in at least one field;\n* If \"ADDED\", then only `after` will be present;\n* If \"DELETED\", then only `before` will be present.",
            "enum" : [
              "ADDED",
              "DELETED",
              "MODIFIED"
            ]
          }
        },
        "description" : "Represents a diff entry between two records returned by the same NQE query."
      },
      "NqeDiffRequest" : {
        "required" : [
          "queryId"
        ],
        "type" : "object",
        "properties" : {
          "queryId" : {
            "type" : "string",
            "description" : "The query identifier of the query to run, referenced by its NQE Library Query ID.",
            "examples" : [
              "FQ_ac651cb2901b067fe7dbfb511613ab44776d8029"
            ]
          },
          "commitId" : {
            "type" : "string",
            "description" : "Version of the query identified by `queryId` to run. Omit to run the latest version. Required if the query identified by `queryId` has been deleted.",
            "examples" : [
              "84f84b0c0a0a1805ddff0ca5451c2c55c58605e5"
            ]
          },
          "options" : {
            "$ref" : "#/components/schemas/NqeQueryOptions"
          }
        }
      },
      "NqeDiffResult" : {
        "type" : "object",
        "properties" : {
          "rows" : {
            "type" : "array",
            "description" : "The NQE query diff's rows, as a list of objects. Each object represents either an added row, a deleted row, or a modified row. In the case of a modified row, the before and after rows are matched up by their values on the key columns for the before and after tables. In particular, the key columns are the smallest set of left-most columns that uniquely identify rows within the before table and the after table.",
            "items" : {
              "$ref" : "#/components/schemas/NqeDiffEntry"
            }
          },
          "totalNumRows" : {
            "type" : "integer",
            "description" : "The number of diff rows that would be present if there was no limit.\nIf there are column filters, then it should be the number of rows that satisfy the column filters (if there were no limit).",
            "format" : "int32"
          }
        }
      },
      "NqeErrorInfo" : {
        "required" : [
          "apiUrl",
          "httpMethod",
          "message"
        ],
        "type" : "object",
        "properties" : {
          "completionType" : {
            "type" : "string",
            "enum" : [
              "FINISHED",
              "CANCELED",
              "TIMED_OUT"
            ]
          },
          "errors" : {
            "type" : "array",
            "items" : {
              "$ref" : "#/components/schemas/NqeQueryError"
            }
          },
          "snapshotId" : {
            "type" : "string",
            "description" : "The ID of the Snapshot the query was run against.",
            "examples" : [
              "101"
            ]
          },
          "httpMethod" : {
            "type" : "string",
            "examples" : [
              "GET"
            ],
            "enum" : [
              "GET",
              "HEAD",
              "POST",
              "PUT",
              "PATCH",
              "DELETE"
            ]
          },
          "apiUrl" : {
            "type" : "string",
            "examples" : [
              "/api/version"
            ]
          },
          "message" : {
            "type" : "string",
            "description" : "A description of the error"
          },
          "reason" : {
            "type" : "string"
          }
        }
      },
      "NqeQuery" : {
        "type" : "object",
        "properties" : {
          "queryId" : {
            "type" : "string",
            "description" : "The ID of the query",
            "examples" : [
              "FQ_ac651cb2901b067fe7dbfb511613ab44776d8029"
            ]
          },
          "repository" : {
            "type" : "string",
            "examples" : [
              "ORG"
            ],
            "enum" : [
              "FWD",
              "ORG"
            ]
          },
          "path" : {
            "type" : "string",
            "description" : "The unique path of the query, including its name, in the latest commit",
            "examples" : [
              "/L2/MtuConsistency"
            ]
          },
          "intent" : {
            "type" : "string",
            "description" : "The intent of the query in the latest commit"
          }
        }
      },
      "NqeQueryError" : {
        "type" : "object",
        "properties" : {
          "location" : {
            "$ref" : "#/components/schemas/TextRegion",
            "description" : "The region in the original query that caused the error."
          },
          "message" : {
            "type" : "string",
            "description" : "The error's message."
          }
        }
      },
      "NqeQueryOptions" : {
        "type" : "object",
        "properties" : {
          "offset" : {
            "type" : "integer",
            "description" : "(optional) The number of initial records to skip. Defaults to 0. Cannot be negative.",
            "format" : "int32",
            "examples" : [
              20
            ]
          },
          "limit" : {
            "type" : "integer",
            "description" : "(optional) The maximum number of records to return. Defaults to 1000. Must be positive and must not exceed 10000.",
            "format" : "int32",
            "examples" : [
              100
            ]
          },
          "sortBy" : {
            "$ref" : "#/components/schemas/SortOrder",
            "description" : "(optional) An object specifying how results should be sorted."
          },
          "columnFilters" : {
            "type" : "array",
            "description" : "(optional) Result filters. Only records that match all filters are returned. A record matches the array of `columnFilters` if the record matches all of the `columnFilters`, in which case it is kept in the results.",
            "examples" : [
              [
                {
                  "columnName" : "Name",
                  "value" : "MyDeviceName"
                }
              ]
            ],
            "items" : {
              "$ref" : "#/components/schemas/ColumnFilter"
            }
          }
        }
      },
      "NqeQueryRunRequest" : {
        "type" : "object",
        "properties" : {
          "query" : {
            "type" : "string",
            "description" : "The source code of the query to run. Exactly one of `queryId` or `query` must be provided.",
            "examples" : [
              "foreach d in network.devices select { Name: d.name }"
            ]
          },
          "queryId" : {
            "type" : "string",
            "description" : "The query identifier of the query to run, referenced by its NQE Library Query ID. Exactly one of `queryId` or `query` must be provided. This identifier can be found in the information callout in the Queries pane or the Versions view dropdown.",
            "examples" : [
              "FQ_ac651cb2901b067fe7dbfb511613ab44776d8029"
            ]
          },
          "commitId" : {
            "type" : "string",
            "description" : "Version of the query identified by `queryId` to run. Omit to run the latest version. Required if the query identified by `queryId` has been deleted. This identifier can be found in the information callout in the Queries pane or the Versions view dropdown.",
            "examples" : [
              "84f84b0c0a0a1805ddff0ca5451c2c55c58605e5"
            ]
          },
          "queryOptions" : {
            "$ref" : "#/components/schemas/NqeQueryRunRequestOptions"
          },
          "parameters" : {
            "type" : "object",
            "additionalProperties" : { },
            "description" : "Values for each parameter declared in the query. The parameter values are specified as a JSON object, with one property per parameter, where the property name matches the parameter name. The property value is the JSON representation of the parameter value. The JSON representation of a parameter value depends on the type of the value. For values of type `String`, `IpAddress`, `IpSubnet`, and `MacAddress`, the JSON representation is a JSON string. For values of type `Number`, the value is an integral JSON number. For values of type `Boolean`, the JSON representation is true or false. For values of type `List<T>`, the JSON representation is an array of JSON values, each of which is a JSON representation for type `T`. For record values, the JSON representation is a JSON object with corresponding properties whose values are JSON representations corresponding to the properties' types. For enumerations, the JSON representation is a JSON string with the enum constant name. For `oneOf` values that contain data, the JSON representation is a JSON object with two properties, `alternative` and `value`, where the `alternative` property contains the alternative's name (a string) and the `value` property is a JSON representation of the data associated with this alternative.",
            "examples" : [
              {
                "mtuThreshold" : 123,
                "ntpServers" : [
                  "10.22.2.3",
                  "192.33.4.1"
                ]
              }
            ]
          }
        }
      },
      "NqeQueryRunRequestOptions" : {
        "type" : "object",
        "properties" : {
          "offset" : {
            "type" : "integer",
            "description" : "(optional) The number of initial records to skip. Defaults to 0. Cannot be negative.",
            "format" : "int32",
            "examples" : [
              20
            ]
          },
          "limit" : {
            "type" : "integer",
            "description" : "(optional) The maximum number of records to return. Defaults to 1000. Must be positive and must not exceed 10000.",
            "format" : "int32",
            "examples" : [
              100
            ]
          },
          "sortBy" : {
            "$ref" : "#/components/schemas/SortOrder",
            "description" : "(optional) An object specifying how results should be sorted."
          },
          "columnFilters" : {
            "type" : "array",
            "description" : "(optional) Result filters. Only records that match all filters are returned. A record matches the array of `columnFilters` if the record matches all of the `columnFilters`, in which case it is kept in the results.",
            "examples" : [
              [
                {
                  "columnName" : "Name",
                  "value" : "MyDeviceName"
                }
              ]
            ],
            "items" : {
              "$ref" : "#/components/schemas/ColumnFilter"
            }
          },
          "itemFormat" : {
            "type" : "string",
            "description" : "(optional) Specifies how each row in the result should be rendered. If set to LEGACY (the default), complex values in the row are rendered as strings. If set to JSON, complex values are rendered as JSON arrays and records. A complex value is one that is not a scalar (such as a number, string, enum value, date, etc.), or is not a list of scalar values.",
            "examples" : [
              "JSON"
            ],
            "enum" : [
              "JSON",
              "LEGACY"
            ]
          }
        }
      },
      "NqeRecord" : {
        "type" : "object",
        "properties" : {
          "fields" : {
            "type" : "object",
            "additionalProperties" : {
              "$ref" : "#/components/schemas/CellValue"
            }
          }
        }
      },
      "NqeRunResult" : {
        "type" : "object",
        "properties" : {
          "snapshotId" : {
            "type" : "string",
            "description" : "The ID of the Snapshot that the query was run against.",
            "examples" : [
              "101"
            ]
          },
          "items" : {
            "type" : "array",
            "description" : "The query's results, as a list of objects. Each object corresponds to a record returned by the query, and is an object with fields of simple values, where a simple value is either a basic value or a list of basic values. A basic value is either a number, boolean, string, or null.",
            "examples" : [
              [
                {
                  "boolField" : true,
                  "numField" : 1,
                  "nullField" : null,
                  "stringField" : "string",
                  "listField" : [
                    1,
                    2,
                    3
                  ]
                }
              ]
            ],
            "items" : {
              "$ref" : "#/components/schemas/NqeRecord"
            }
          },
          "totalNumItems" : {
            "type" : "integer",
            "description" : "The total number of items in the query result. This number could be different than the length of `items` if a filter is used or if the total size of the rows would exceed the maximum page size of 400MB.",
            "format" : "int64"
          }
        }
      },
      "SortOrder" : {
        "required" : [
          "columnName"
        ],
        "type" : "object",
        "properties" : {
          "columnName" : {
            "type" : "string",
            "description" : "The name of a column to sort on.",
            "examples" : [
              "Name"
            ]
          },
          "order" : {
            "type" : "string",
            "description" : "(optional) Either \"ASC\" or \"DESC\" to sort ascending or descending, respectively. Defaults to \"ASC\".",
            "examples" : [
              "ASC"
            ],
            "enum" : [
              "ASC",
              "DESC"
            ]
          }
        }
      },
      "TextPosition" : {
        "type" : "object",
        "properties" : {
          "character" : {
            "type" : "integer",
            "description" : "Position on the line (by number of characters, starting at 0)",
            "format" : "int32"
          },
          "line" : {
            "type" : "integer",
            "description" : "Line number (starting at 0)",
            "format" : "int32"
          }
        }
      },
      "TextRegion" : {
        "type" : "object",
        "properties" : {
          "start" : {
            "$ref" : "#/components/schemas/TextPosition",
            "description" : "The region's starting position (starting at (0, 0))."
          },
          "end" : {
            "$ref" : "#/components/schemas/TextPosition",
            "description" : "The region's ending position."
          }
        }
      }
    },
    "securitySchemes" : {
      "api_token" : {
        "type" : "http",
        "scheme" : "basic"
      }
    }
  }
}