{
  "openapi": "3.1.0",
  "info": {
    "title": "Forward Networks: NQE API",
    "summary": "Ask the Network Query Engine for structured, vendor-agnostic network information",
    "description": "Network Query Engine (NQE) enables you to query for information about your network. For more information about NQE\nqueries and for help writing queries, see the\n[NQE tutorial](https://docs.fwd.app/latest/application/nqe/nqe_tutorial/) or the Data Model tab of the\n[Help pane](https://docs.fwd.app/latest/application/nqe/nqe_library/#help-pane) in the NQE Library.\n\nThe NQE API allows you to run NQE queries on a network Snapshot. You may also filter and order the results by\nproviding a `QueryOptions` object.",
    "contact": {
      "email": "support@forwardnetworks.com"
    },
    "license": {
      "name": "MIT",
      "url": "https://spdx.org/licenses/MIT"
    },
    "version": "${apiVersion}"
  },
  "servers": [
    {
      "url": "/api"
    }
  ],
  "security": [
    {
      "api_token": []
    }
  ],
  "tags": [
    {
      "name": "NQE",
      "description": "Ask the Network Query Engine for structured, vendor-agnostic network information"
    }
  ],
  "paths": {
    "/nqe": {
      "post": {
        "tags": [
          "NQE"
        ],
        "summary": "Run an NQE query",
        "operationId": "runNqeQuery",
        "parameters": [
          {
            "name": "networkId",
            "in": "query",
            "description": "The ID of the Network to query. Required unless the `snapshotId` parameter is provided.",
            "schema": {
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/SnapshotId"
          }
        ],
        "requestBody": {
          "description": "In the example request body, up to 100 rows are requested, starting from row 20, from the results consisting\nof all the rows, sorted by the `Name` column in ascending order, and limiting to those rows whose `Name`\nproperty contains `MyDeviceName`. Note that the sample JSON object contains both the `query` and `queryId`\nproperties and therefore is NOT a valid request. If you use this example for testing, then make sure to remove\none of them. The example `parameters` object is only there as an example. It is not needed for either of the\nreferenced queries. The referenced query must define parameters `mtuThreshold` of type `Integer` and\n`ntpServers` of type `List<IpAddress>` for these values to be valid.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NqeQueryRunRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "The response contains the query's results in the `items` property.",
            "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\nwere invalid, or the query timed out or was cancelled during execution. The response will contain\n`completionType`, `errors`, and `snapshotId` properties that provide detailed information on the errors. See\nmodel for more information. Note that a response with a 400 code can happen for other errors, such as a lack\nof permission to execute the query, or a request that specified a Query ID for a deleted query without also\nspecifying a Commit ID. In such cases, the `completionType`, `errors`, and `snapshotId` properties will be\nomitted from the response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NqeErrorInfo"
                }
              }
            }
          }
        }
      }
    },
    "/nqe-diffs/{before}/{after}": {
      "post": {
        "tags": [
          "NQE"
        ],
        "summary": "Compare NQE query results",
        "description": "Identifies differences in the results of an NQE query for two Snapshots of a network.",
        "operationId": "getNqeQueryDiff",
        "parameters": [
          {
            "name": "before",
            "in": "path",
            "description": "The ID for the Snapshot to base the diff on.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "after",
            "in": "path",
            "description": "The ID for the Snapshot to diff against the base Snapshot.",
            "required": true,
            "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\ncallout of a query listed in the Queries pane). The `commitId` property contains a Commit ID of the query\nidentified by `queryId` (this can also be found in either the information callout in the Queries pane, or in\nthe callout in the Versions view dropdown). Use `commitId` to run a specific version of the query. The\n`options` property is optional and can be used to refine the results and/or specify the JSON format. In the\nsample object below, `options` requests up to 100 rows, starting from row 20, from the results consisting of\nall the rows, sorted by `Name` column in ascending order and limited to those rows whose `Name` property\ncontains `ATL`, rendered with JSON arrays and objects instead of strings. The `options` property also allows\nfor sorting and filtering on the diff change type column. To do this, set the `columnName` value on either the\n`sortBy` or `columnFilters` property to `ChangeType`. It has three possible values: `MODIFIED`, `ADDED`, or\n`DELETED`. The `parameters` property can be omitted if the query has no declared parameters. If the query\ndeclares parameters, the `parameters` property should contain a JSON object providing the values for the\nparameters to use while executing the query for this request. The provided parameter values must match the\nparameter types declared in the NQE query.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NqeDiffRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "The response contains the query's diff results in the `rows` property.",
            "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\ninvalid, the `options` for the query were invalid, the query and/or diff timed out or was cancelled during\nexecution, or the user does not have permission to execute the query.",
            "content": {}
          }
        }
      }
    },
    "/nqe/queries": {
      "get": {
        "tags": [
          "NQE"
        ],
        "summary": "List all NQE queries",
        "operationId": "getNqeQueries",
        "parameters": [
          {
            "name": "dir",
            "in": "query",
            "description": "If specified, include only queries in the given directory. The directory must start and end with a forward\nslash, such as `/L3/Advanced/`.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/NqeQuery"
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "NqeDiffRequest": {
        "type": "object",
        "required": [
          "queryId"
        ],
        "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\nidentified by `queryId` has been deleted.",
            "examples": [
              "84f84b0c0a0a1805ddff0ca5451c2c55c58605e5"
            ]
          },
          "options": {
            "$ref": "#/components/schemas/NqeQueryOptions"
          }
        }
      },
      "NqeDiffResult": {
        "type": "object",
        "properties": {
          "rows": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/NqeDiffEntry"
            },
            "description": "The NQE query diff's rows, as a list of objects. Each object represents either an added row, a deleted row,\nor a modified row. In the case of a modified row, the before and after rows are matched up by their values\non the key columns for the before and after tables. In particular, the key columns are the smallest set of\nleft-most columns that uniquely identify rows within the before table and the after table."
          },
          "totalNumRows": {
            "type": "integer",
            "format": "int32",
            "description": "The number of diff rows that would be present if there were no limit. If there are column filters, then it is the\nnumber of rows that satisfy the column filters (if there were no limit)."
          }
        }
      },
      "NqeErrorInfo": {
        "type": "object",
        "required": [
          "httpMethod",
          "apiUrl",
          "message"
        ],
        "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"
          }
        }
      },
      "NqeQueryRunRequest": {
        "type": "object",
        "properties": {
          "query": {
            "type": "string",
            "description": "The source code of the query to run. Used to directly run a query. Exactly one of `queryId` or `query` must be\nprovided.",
            "examples": [
              "foreach d in network.devices select { Name: d.name }"
            ]
          },
          "queryId": {
            "type": "string",
            "description": "The Query ID of a committed query in NQE Library. Used to run a query identified by its Query ID. Exactly one of\n`queryId` or `query` must be provided. This identifier can be found in the information callout in the Queries pane\nor the Versions view dropdown.",
            "examples": [
              "FQ_ac651cb2901b067fe7dbfb511613ab44776d8029"
            ]
          },
          "commitId": {
            "type": "string",
            "description": "A Commit ID of the query identified by the `queryId` property. Used to run a specific version of a committed\nquery. Omit to run the latest version. Required if the query identified by `queryId` has been deleted. This\nidentifier can be found in the information callout in the Queries pane or the Versions view dropdown.",
            "examples": [
              "84f84b0c0a0a1805ddff0ca5451c2c55c58605e5"
            ]
          },
          "queryOptions": {
            "$ref": "#/components/schemas/NqeQueryOptions",
            "description": "(optional) Options to refine and display the results."
          },
          "parameters": {
            "type": "object",
            "description": "Values for each parameter declared in the query. Can be omitted if the query has no declared parameters. The\nparameter values are specified as a JSON object, with one property per parameter, where the property name matches\nthe parameter name. The property value is the JSON representation of the parameter value. The JSON representation\nof a parameter value depends on the type of the value. For values of type `String`, `IpAddress`, `IpSubnet`, and\n`MacAddress`, the JSON representation is a JSON string. For values of type `Number`, the value is an integral JSON\nnumber. For values of type `Boolean`, the JSON representation is true or false. For values of type `List<T>`, the\nJSON representation is an array of JSON values, each of which is a JSON representation for type `T`. For record\nvalues, the JSON representation is a JSON object with corresponding properties whose values are JSON\nrepresentations corresponding to the properties' types. For enumerations, the JSON representation is a JSON string\nwith the enum constant name. For `oneOf` values that contain data, the JSON representation is a JSON object with\ntwo properties, `alternative` and `value`, where the `alternative` property contains the alternative's name (a\nstring) 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"
                ]
              }
            ]
          }
        }
      },
      "NqeRunResult": {
        "type": "object",
        "properties": {
          "snapshotId": {
            "type": "string",
            "description": "The ID of the Snapshot that the query was run against.",
            "examples": [
              "101"
            ]
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/NqeRecord"
            },
            "description": "The query's results, as a list of objects. Each object corresponds to a row returned by the query, and is an\nobject with properties of simple values, where a simple value is either a basic value or a list of basic values. A\nbasic value is either a number, boolean, string, or null.",
            "examples": [
              [
                {
                  "boolField": true,
                  "numField": 1,
                  "nullField": null,
                  "stringField": "string",
                  "listField": [
                    1,
                    2,
                    3
                  ]
                }
              ]
            ]
          },
          "totalNumItems": {
            "type": "integer",
            "format": "int64",
            "description": "The total number of items in the query's results. This number could be different than the length of `items` if a\nfilter is used or if the total size of the rows would exceed the maximum page size of 400MB."
          }
        }
      },
      "SortOrder": {
        "type": "object",
        "required": [
          "columnName"
        ],
        "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"
            ]
          }
        }
      },
      "DefaultColumnFilter": {
        "type": "object",
        "required": [
          "columnName"
        ],
        "properties": {
          "columnName": {
            "type": "string",
            "description": "The name of a column to filter on.",
            "examples": [
              "Name"
            ]
          },
          "operator": {
            "type": "string",
            "const": "DEFAULT"
          },
          "value": {
            "type": "string",
            "description": "A value (in its string representation) to match on.",
            "examples": [
              "ATL"
            ]
          }
        }
      },
      "BetweenColumnFilter": {
        "type": "object",
        "required": [
          "columnName",
          "operator"
        ],
        "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\nomitted.",
            "examples": [
              "2023-07-30T08:27:16Z"
            ]
          },
          "operator": {
            "type": "string",
            "const": "IS_BETWEEN"
          },
          "upperBound": {
            "type": "string",
            "description": "A value (in its string representation) to limit on inclusively from above. Required if 'lowerBound' is\nomitted.",
            "examples": [
              "2025-07-30T08:27:16Z"
            ]
          }
        }
      },
      "ColumnFilter": {
        "type": "object",
        "required": [
          "operator"
        ],
        "properties": {
          "operator": {
            "type": "string",
            "enum": [
              "DEFAULT",
              "IS_BETWEEN"
            ]
          }
        },
        "oneOf": [
          {
            "$ref": "#/components/schemas/DefaultColumnFilter"
          },
          {
            "$ref": "#/components/schemas/BetweenColumnFilter"
          }
        ],
        "discriminator": {
          "propertyName": "operator",
          "mapping": {
            "DEFAULT": "#/components/schemas/DefaultColumnFilter",
            "IS_BETWEEN": "#/components/schemas/BetweenColumnFilter"
          }
        }
      },
      "NqeQueryOptions": {
        "type": "object",
        "properties": {
          "offset": {
            "type": "integer",
            "format": "int32",
            "description": "(optional) The number of initial rows to skip. Defaults to 0. Cannot be negative.",
            "examples": [
              20
            ]
          },
          "limit": {
            "type": "integer",
            "format": "int32",
            "description": "(optional) The maximum number of rows to return. Defaults to 1,000. Must be positive.\nCannot exceed 10,000.",
            "examples": [
              100
            ]
          },
          "sortBy": {
            "$ref": "#/components/schemas/SortOrder",
            "description": "(optional) Specifies how results should be sorted."
          },
          "columnFilters": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ColumnFilter"
            },
            "description": "(optional) A collection of conditions on column values for filtering the results. A row matches the array of\n`columnFilters` if the row matches all of the `columnFilters`, in which case it is kept in the results.",
            "examples": [
              [
                {
                  "columnName": "Name",
                  "value": "MyDeviceName"
                }
              ]
            ]
          },
          "itemFormat": {
            "type": "string",
            "description": "(optional) Specifies how each row in the results should be rendered.\n\nIf set to `JSON`, then complex values are rendered as JSON arrays and records.\nIf set to `LEGACY`, then complex values in the row are rendered as strings.\n\nA complex value is one that is not a scalar (such as a number, string, enum value, date, etc.) and is not a list\nof scalar values.\n\n**Note:** The `LEGACY` format is deprecated and will be removed in release 26.9.",
            "examples": [
              "JSON"
            ],
            "default": "JSON",
            "enum": [
              "JSON",
              "LEGACY"
            ]
          }
        }
      },
      "CellValue": {
        "type": "object"
      },
      "NqeRecord": {
        "type": "object",
        "properties": {
          "fields": {
            "type": "object",
            "additionalProperties": {
              "$ref": "#/components/schemas/CellValue"
            }
          }
        }
      },
      "TextPosition": {
        "type": "object",
        "properties": {
          "character": {
            "type": "integer",
            "format": "int32",
            "description": "Position on the line (by number of characters, starting at 0)"
          },
          "line": {
            "type": "integer",
            "format": "int32",
            "description": "Line number (starting at 0)"
          }
        }
      },
      "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."
          }
        }
      },
      "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."
          }
        }
      },
      "NqeDiffEntry": {
        "type": "object",
        "properties": {
          "after": {
            "$ref": "#/components/schemas/NqeRecord",
            "description": "The row returned by the query against the 'after' snapshot. Not present if `type` is `DELETED`."
          },
          "before": {
            "$ref": "#/components/schemas/NqeRecord",
            "description": "The row 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 property;\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."
      }
    },
    "parameters": {
      "SnapshotId": {
        "name": "snapshotId",
        "in": "query",
        "description": "An optional Snapshot id. If omitted, the network’s latest processed Snapshot is used.",
        "schema": {
          "type": "string"
        }
      }
    },
    "securitySchemes": {
      "api_token": {
        "type": "http",
        "scheme": "basic"
      }
    }
  }
}