# REST API Reference

This document is the authoritative specification of the OPA REST API. The API can be broken down into the following groups:

*   [Policy API](#policy-api) - manage policy loaded into the OPA instance.
*   [Data API](#data-api) - evaluate rules and retrieve data.
*   [Query API](#query-api) - execute ad hoc queries.
*   [Compile API](#compile-api) - access Rego's [Partial Evaluation](https://blog.openpolicyagent.org/partial-evaluation-162750eaf422) and data filtering functionality.
*   [Health API](#health-api) - access instance operational health information.
*   [Config API](#config-api) - view instance configuration.
*   [Status API](#status-api) - view instance [status](/docs/management-status) state.

The REST API is a common way to integrate with OPA.

[(17 projects)](/ecosystem/by-feature/rest-api-integration)

You may also want to review the [integration documentation](/docs/integration) for other options to build on OPA by embedding functionality directly into your application.

info

Integrating with OPA from a programming language? You might find it easier to build your OPA integration using one of the [language SDKs](/ecosystem#languages) than working with the REST API directly.

## Common Request Headers

The following request headers are commonly used in some API endpoints:

### Content-Type

It indicates the request body format. These are some values used in some APIs:

*   `application/json` for JSON encoded content, e.g. a JSON document
*   `application/yaml` for YAML encoded content, e.g. a YAML document
*   `text/plain` for plain text content, e.g. a policy

Accept-Encoding

It could have `gzip` value which indicates the server should respond with a Gzip encoded body. The server will send the compressed response only if its length is above `server.encoding.gzip.min_length` value. See the [configuration section](/docs/configuration#server).

Content-Encoding

It could have `gzip` value which indicates the request body is a gzip encoded object.

## Policy API

The Policy API exposes CRUD endpoints for managing policy modules. Policy modules can be added, removed, and modified at any time.

The identifiers given to policy modules are only used for management purposes in the REST API and are not used outside the Policy API. OPA uses identifiers to refer to individual policy files loaded into OPA. These might come from a bundle, a file or from the policy path fragment (`<id>`) used when inserting via the API. They are unrelated to the file's package and if you are unsure of a value to use, you can use the name of the file containing the policy, e.g. `authz.rego`. Note that `opa run -s file.rego` will have `file.rego` as the ID in the Policy API.

### List Policies

```
GET /v1/policies HTTP/1.1
```

List policy modules.

Status Codes

*   **200** - no error
*   **500** - server error

Example Request

```
GET /v1/policies HTTP/1.1
```

Example Response

```
HTTP/1.1 200 OKContent-Type: application/json
```

```
{  "result": [    {      "id": "example2",      "raw": "package opa.examples\n\nimport data.servers\n\nviolations[server] {\n\tserver = servers[_]\n\tserver.protocols[_] = \"http\"\n\tpublic_servers[server]\n}\n",      "ast": {        "package": {          "path": [            {              "type": "var",              "value": "data"            },            {              "type": "string",              "value": "opa"            },            {              "type": "string",              "value": "examples"            }          ]        },        "rules": [          {            "head": {              "name": "violations",              "key": {                "type": "var",                "value": "server"              }            },            "body": [              {                "index": 0,                "terms": [                  {                    "type": "string",                    "value": "eq"                  },                  {                    "type": "var",                    "value": "server"                  },                  {                    "type": "ref",                    "value": [                      {                        "type": "var",                        "value": "data"                      },                      {                        "type": "string",                        "value": "servers"                      },                      {                        "type": "var",                        "value": "$0"                      }                    ]                  }                ]              },              {                "index": 1,                "terms": [                  {                    "type": "string",                    "value": "eq"                  },                  {                    "type": "ref",                    "value": [                      {                        "type": "var",                        "value": "server"                      },                      {                        "type": "string",                        "value": "protocols"                      },                      {                        "type": "var",                        "value": "$1"                      }                    ]                  },                  {                    "type": "string",                    "value": "http"                  }                ]              },              {                "index": 2,                "terms": {                  "type": "ref",                  "value": [                    {                      "type": "var",                      "value": "data"                    },                    {                      "type": "string",                      "value": "opa"                    },                    {                      "type": "string",                      "value": "examples"                    },                    {                      "type": "string",                      "value": "public_servers"                    },                    {                      "type": "var",                      "value": "server"                    }                  ]                }              }            ]          }        ]      }    },    {      "id": "example1",      "raw": "package opa.examples\n\nimport data.servers\nimport data.networks\nimport data.ports\n\npublic_servers[server] {\n\tserver = servers[_]\n\tserver.ports[_] = ports[k].id\n\tports[k].networks[_] = networks[m].id\n\tnetworks[m].public = true\n}\n",      "ast": {        "package": {          "path": [            {              "type": "var",              "value": "data"            },            {              "type": "string",              "value": "opa"            },            {              "type": "string",              "value": "examples"            }          ]        },        "rules": [          {            "head": {              "name": "public_servers",              "key": {                "type": "var",                "value": "server"              }            },            "body": [              {                "index": 0,                "terms": [                  {                    "type": "string",                    "value": "eq"                  },                  {                    "type": "var",                    "value": "server"                  },                  {                    "type": "ref",                    "value": [                      {                        "type": "var",                        "value": "data"                      },                      {                        "type": "string",                        "value": "servers"                      },                      {                        "type": "var",                        "value": "$0"                      }                    ]                  }                ]              },              {                "index": 1,                "terms": [                  {                    "type": "string",                    "value": "eq"                  },                  {                    "type": "ref",                    "value": [                      {                        "type": "var",                        "value": "server"                      },                      {                        "type": "string",                        "value": "ports"                      },                      {                        "type": "var",                        "value": "$1"                      }                    ]                  },                  {                    "type": "ref",                    "value": [                      {                        "type": "var",                        "value": "data"                      },                      {                        "type": "string",                        "value": "ports"                      },                      {                        "type": "var",                        "value": "k"                      },                      {                        "type": "string",                        "value": "id"                      }                    ]                  }                ]              },              {                "index": 2,                "terms": [                  {                    "type": "string",                    "value": "eq"                  },                  {                    "type": "ref",                    "value": [                      {                        "type": "var",                        "value": "data"                      },                      {                        "type": "string",                        "value": "ports"                      },                      {                        "type": "var",                        "value": "k"                      },                      {                        "type": "string",                        "value": "networks"                      },                      {                        "type": "var",                        "value": "$2"                      }                    ]                  },                  {                    "type": "ref",                    "value": [                      {                        "type": "var",                        "value": "data"                      },                      {                        "type": "string",                        "value": "networks"                      },                      {                        "type": "var",                        "value": "m"                      },                      {                        "type": "string",                        "value": "id"                      }                    ]                  }                ]              },              {                "index": 3,                "terms": [                  {                    "type": "string",                    "value": "eq"                  },                  {                    "type": "ref",                    "value": [                      {                        "type": "var",                        "value": "data"                      },                      {                        "type": "string",                        "value": "networks"                      },                      {                        "type": "var",                        "value": "m"                      },                      {                        "type": "string",                        "value": "public"                      }                    ]                  },                  {                    "type": "boolean",                    "value": true                  }                ]              }            ]          }        ]      }    }  ]}
```

### Get a Policy

```
GET /v1/policies/<id>
```

Get a policy module.

Query Parameters

*   **pretty** - If parameter is `true`, response will be formatted for humans.

Status Codes

*   **200** - no error
*   **404** - not found
*   **500** - server error

Example Request

```
GET /v1/policies/example1 HTTP/1.1
```

Example Response

```
HTTP/1.1 200 OKContent-Type: application/json
```

```
{  "result": {    "id": "example1",    "raw": "package opa.examples\n\nimport data.servers\nimport data.networks\nimport data.ports\n\npublic_servers[server] {\n\tserver = servers[_]\n\tserver.ports[_] = ports[k].id\n\tports[k].networks[_] = networks[m].id\n\tnetworks[m].public = true\n}\n",    "ast": {      "package": {        "path": [          {            "type": "var",            "value": "data"          },          {            "type": "string",            "value": "opa"          },          {            "type": "string",            "value": "examples"          }        ]      },      "rules": [        {          "head": {            "name": "public_servers",            "key": {              "type": "var",              "value": "server"            }          },          "body": [            {              "index": 0,              "terms": [                {                  "type": "string",                  "value": "eq"                },                {                  "type": "var",                  "value": "server"                },                {                  "type": "ref",                  "value": [                    {                      "type": "var",                      "value": "data"                    },                    {                      "type": "string",                      "value": "servers"                    },                    {                      "type": "var",                      "value": "$0"                    }                  ]                }              ]            },            {              "index": 1,              "terms": [                {                  "type": "string",                  "value": "eq"                },                {                  "type": "ref",                  "value": [                    {                      "type": "var",                      "value": "server"                    },                    {                      "type": "string",                      "value": "ports"                    },                    {                      "type": "var",                      "value": "$1"                    }                  ]                },                {                  "type": "ref",                  "value": [                    {                      "type": "var",                      "value": "data"                    },                    {                      "type": "string",                      "value": "ports"                    },                    {                      "type": "var",                      "value": "k"                    },                    {                      "type": "string",                      "value": "id"                    }                  ]                }              ]            },            {              "index": 2,              "terms": [                {                  "type": "string",                  "value": "eq"                },                {                  "type": "ref",                  "value": [                    {                      "type": "var",                      "value": "data"                    },                    {                      "type": "string",                      "value": "ports"                    },                    {                      "type": "var",                      "value": "k"                    },                    {                      "type": "string",                      "value": "networks"                    },                    {                      "type": "var",                      "value": "$2"                    }                  ]                },                {                  "type": "ref",                  "value": [                    {                      "type": "var",                      "value": "data"                    },                    {                      "type": "string",                      "value": "networks"                    },                    {                      "type": "var",                      "value": "m"                    },                    {                      "type": "string",                      "value": "id"                    }                  ]                }              ]            },            {              "index": 3,              "terms": [                {                  "type": "string",                  "value": "eq"                },                {                  "type": "ref",                  "value": [                    {                      "type": "var",                      "value": "data"                    },                    {                      "type": "string",                      "value": "networks"                    },                    {                      "type": "var",                      "value": "m"                    },                    {                      "type": "string",                      "value": "public"                    }                  ]                },                {                  "type": "boolean",                  "value": true                }              ]            }          ]        }      ]    }  }}
```

### Create or Update a Policy

```
PUT /v1/policies/<id>Content-Type: text/plain
```

Create or update a policy module.

If the policy module does not exist, it is created. If the policy module already exists, it is replaced.

info

[Bundles](/docs/management-bundles) are the preferred way to update policies and are best suited for most use cases. Bundles provide eventually consistent updates and better support for deployments with many OPA instances than manual API calls to set policies.

Note that if a package path is owned by a loaded Bundle, you will not be able to update this path using the Policy API.

Request Headers

*   **[Content-Type](#content-type)**: `text/plain`

Query Parameters

*   **pretty** - If parameter is `true`, response will be formatted for humans.
*   **metrics** - Return compiler performance metrics in addition to result. See [Performance Metrics](#performance-metrics) for more detail.

Status Codes

*   **200** - no error
*   **400** - bad request
*   **500** - server error

Before accepting the request, the server will parse, compile, and install the policy module. If the policy module is invalid, one of these steps will fail and the server will respond with 400. The error message in the response will be set to indicate the source of the error.

Example Request

```
PUT /v1/policies/example1 HTTP/1.1Content-Type: text/plain
```

```
package opa.examplesimport data.networksimport data.portsimport data.serverspublic_servers contains server if {    some k, m    server := servers[_]    server.ports[_] == ports[k].id    ports[k].networks[_] == networks[m].id    networks[m].public == true}
```

> cURL's `-d/--data` flag removes newline characters from input files. Use the `--data-binary` flag instead.

Example Response

```
HTTP/1.1 200 OKContent-Type: application/json
```

```
{}
```

### Delete a Policy

```
DELETE /v1/policies/<id>
```

Delete a policy module.

Query Parameters

*   **pretty** - If parameter is `true`, response will be formatted for humans.
*   **metrics** - Return compiler performance metrics in addition to result. See [Performance Metrics](#performance-metrics) for more detail.

Status Codes

*   **200** - no error
*   **400** - bad request
*   **404** - not found
*   **500** - server error

If other policy modules in the same package depend on rules in the policy module to be deleted, the server will return 400.

Example Request

```
DELETE /v1/policies/example2 HTTP/1.1
```

Example Response

```
HTTP/1.1 200 OKContent-Type: application/json
```

```
{}
```

## Data API

The Data API exposes endpoints for reading and writing documents in OPA. For an explanation to the different types of documents in OPA see [How Does OPA Work?](/docs/philosophy#how-does-opa-work)

### Get a Document

```
GET /v1/data/{path:.+}
```

Get a document.

The path separator is used to access values inside object and array documents. The server attempts to convert path segments to integers. If a path element cannot be converted to an integer, the server will use its string representation.

Request Headers

*   **[Accept-Encoding](#accept-encoding)**: `gzip`

Query Parameters

*   **input** - Provide an input document. Format is a JSON value that will be used as the value for the input document.
*   **pretty** - If parameter is `true`, response will be formatted for humans.
*   **provenance** - If parameter is `true`, response will include build/version info in addition to the result. See [Provenance](#provenance) for more detail.
*   **explain** - Return query explanation in addition to result. Values: **notes**, **fails**, **full**, **debug**.
*   **metrics** - Return query performance metrics in addition to result. See [Performance Metrics](#performance-metrics) for more detail.
*   **instrument** - Instrument query evaluation and return a superset of performance metrics in addition to result. See [Performance Metrics](#performance-metrics) for more detail.
*   **strict-builtin-errors** - Treat built-in function call errors as fatal and return an error immediately.
*   **ids** - Include annotation `id` values of evaluated rules in the response. Rules must have `# METADATA` blocks with an `id` field.

Status Codes

*   **200** - no error
*   **400** - bad request
*   **500** - server error

The server returns 400 if the input document is invalid (i.e. malformed JSON).

The server returns 200 if the path refers to an undefined document. In this case, the response will not contain a `result` property.

Response Message

*   `result` - The base or virtual document referred to by the URL path. If the path is undefined, this key will be omitted.
    
*   `metrics` - If query metrics are enabled, this field contains query performance metrics collected during the parse, compile, and evaluation steps.
    
*   `decision_id` - If decision logging is enabled, this field contains a string that uniquely identifies the decision. The identifier will be included in the decision log event for this decision. Callers can use the identifier for correlation purposes.
    
*   `ids` - If the `ids` query parameter is set, this field contains an array of annotation `id` values for rules that were successfully evaluated.
    

Example Request

```
GET /v1/data/opa/examples/public_servers HTTP/1.1
```

Example Response

```
HTTP/1.1 200 OKContent-Type: application/json
```

```
{  "result": [    {      "id": "s1",      "name": "app",      "ports": [        "p1",        "p2",        "p3"      ],      "protocols": [        "https",        "ssh"      ]    },    {      "id": "s4",      "name": "dev",      "ports": [        "p1",        "p2"      ],      "protocols": [        "http"      ]    }  ]}
```

### Get a Document (with Input)

```
POST /v1/data/{path:.+}Content-Type: application/json
```

```
{  "input": ...}
```

Get a document that requires input.

The path separator is used to access values inside object and array documents. The server attempts to convert path segments to integers. If a path element cannot be converted to an integer, the server will use its string representation.

The request body contains an object that specifies a value for [The input Document](/docs/philosophy#the-opa-document-model).

Any additional top-level keys in the request body beyond `input` are treated as request metadata. See [Request/Response Metadata](#requestresponse-metadata) below.

Request Headers

*   **[Content-Type](#content-type)**: `application/json` or `application/yaml`
*   **[Content-Encoding](#content-encoding)**: `gzip`
*   **[Accept-Encoding](#accept-encoding)**: `gzip`

Query Parameters

*   **pretty** - If parameter is `true`, response will be formatted for humans.
*   **provenance** - If parameter is `true`, response will include build/version info in addition to the result. See [Provenance](#provenance) for more detail.
*   **explain** - Return query explanation in addition to result. Values: **notes**, **fails**, **full**, **debug**.
*   **metrics** - Return query performance metrics in addition to result. See [Performance Metrics](#performance-metrics) for more detail.
*   **instrument** - Instrument query evaluation and return a superset of performance metrics in addition to result. See [Performance Metrics](#performance-metrics) for more detail.
*   **strict-builtin-errors** - Treat built-in function call errors as fatal and return an error immediately.
*   **ids** - Include annotation `id` values of evaluated rules in the response. Rules must have `# METADATA` blocks with an `id` field.

Status Codes

*   **200** - no error
*   **400** - bad request
*   **500** - server error

The server returns 400 if the input document is invalid (i.e. malformed JSON).

The server returns 200 if the path refers to an undefined document. In this case, the response will not contain a `result` property.

Response Message

*   `result` - The base or virtual document referred to by the URL path. If the path is undefined, this key will be omitted.
    
*   `metrics` - If query metrics are enabled, this field contains query performance metrics collected during the parse, compile, and evaluation steps.
    
*   `decision_id` - If decision logging is enabled, this field contains a string that uniquely identifies the decision. The identifier will be included in the decision log event for this decision. Callers can use the identifier for correlation purposes.
    

The examples below assume the following policy:

```
package opa.examplesimport input.example.flagallow_request if flag == true
```

Example Request

```
POST /v1/data/opa/examples/allow_request HTTP/1.1Content-Type: application/json
```

```
{  "input": {    "example": {      "flag": true    }  }}
```

Example Response

```
HTTP/1.1 200 OKContent-Type: application/json
```

```
{  "result": true}
```

Example Request

```
POST /v1/data/opa/examples/allow_request HTTP/1.1Content-Type: application/json
```

```
{  "input": {    "example": {      "flag": false    }  }}
```

Example Response

```
HTTP/1.1 200 OK
```

```
{}
```

Request/Response Metadata

The Data API POST request body may contain additional top-level keys beyond `input`. These are captured as **request metadata** and made available to custom builtins via `BuiltinContext.RequestMetadata` during evaluation. Request metadata is included in [decision log](/docs/management-decision-logs) events under the `custom.request_metadata` field.

Custom builtins registered by wrapping projects can also produce **response metadata** by writing to `BuiltinContext.ResponseMetadata` during evaluation. If any response metadata is produced, it appears as additional top-level fields in the API response and is included in decision log events under `custom.response_metadata`.

In vanilla OPA, no builtins write response metadata, so responses are unchanged.

caution

Future OPA versions may introduce new top-level keys in the request and response bodies. To avoid conflicts, use a unique namespaced key for metadata, e.g. `"com.example.opa/metadata"`.

Example Request

```
POST /v1/data/example/allow HTTP/1.1Content-Type: application/json
```

```
{  "input": {    "user": "alice"  },  "com.example.opa/metadata": {    "corp-id": "acme-42"  }}
```

Example Response

If a custom builtin writes response metadata during evaluation, the response includes those fields alongside the standard ones:

```
HTTP/1.1 200 OKContent-Type: application/json
```

```
{  "decision_id": "04789f85-de5a-477b-8aa5-6d59d7742135",  "result": true,  "com.example.opa/response": {    "version": "v3"  }}
```

Without any response metadata, the response contains only the standard fields:

```
{  "decision_id": "04789f85-de5a-477b-8aa5-6d59d7742135",  "result": true}
```

### Get a Document (Webhook)

```
POST /v0/data/{path:.+}Content-Type: application/json
```

Get a document from a webhook.

Use this API if you are enforcing policy decisions via webhooks that have pre-defined request/response formats. Note, the API path prefix is `/v0` instead of `/v1`.

The request message body defines the content of the [input document](/docs/philosophy#the-opa-document-model). The request message body may be empty. The path separator is used to access values inside object and array documents.

Request Headers

*   **[Content-Type](#content-type)**: `application/json` or `application/yaml`
*   **[Content-Encoding](#content-encoding)**: `gzip`
*   **[Accept-Encoding](#accept-encoding)**: `gzip`

Query Parameters

*   **pretty** - If parameter is `true`, response will be formatted for humans.

Status Codes

*   **200** - no error
*   **400** - bad request
*   **404** - not found
*   **500** - server error

If the requested document is missing or undefined, the server will return 404 and the message body will contain an error object.

The examples below assume the following policy:

```
package opa.examplesimport input.example.flagallow_request if flag == true
```

Example Request

```
POST /v0/data/opa/examples/allow_request HTTP/1.1Content-Type: application/json
```

```
{  "example": {    "flag": true  }}
```

Example Response

```
HTTP/1.1 200 OKContent-Type: application/json
```

```
true
```

### Create or Overwrite a Document

```
PUT /v1/data/{path:.+}Content-Type: application/json
```

Create or overwrite a document.

If the path does not refer to an existing document, the server will attempt to create all the necessary containing documents. This behavior is similar in principle to the Unix command `mkdir -p`.

Request Headers

*   **[Content-Type](#content-type)**: `application/json`
*   **If-None-Match**: `*` - the server will not overwrite an existing document located at the path.

Query Parameters

*   **metrics** - Return performance metrics in addition to result. See [Performance Metrics](#performance-metrics) for more detail.

Status Codes

*   **204** - no content (success)
*   **304** - not modified
*   **400** - bad request
*   **404** - write conflict
*   **500** - server error

If the path refers to a virtual document or a conflicting base document the server will respond with 404. A base document conflict will occur if the parent portion of the path refers to a non-object document.

Example Request To Initialize Document With If-None-Match

```
PUT /v1/data/us-west/servers HTTP/1.1Content-Type: application/jsonIf-None-Match: *
```

```
{}
```

Example Response If Document Already Exists

```
HTTP/1.1 304 Not Modified
```

Example Response If Document Does Not Exist

```
HTTP/1.1 204 No Content
```

### Patch a Document

```
PATCH /v1/data/{path:.+}Content-Type: application/json-patch+json
```

Update a document.

The server accepts updates encoded as JSON Patch operations. The message body of the request should contain a JSON encoded array containing one or more JSON Patch operations. Each operation specifies the operation type, path, and an optional value. For more information on JSON Patch, see [RFC 6902](https://datatracker.ietf.org/doc/html/rfc6902).

The effective path of the JSON Patch operation is obtained by joining the path portion of the URL with the path value from the operation(s) contained in the message body. In all cases, the parent of the effective path MUST refer to an existing document, otherwise the server returns 404. In the case of **remove** and **replace** operations, the effective path MUST refer to an existing document, otherwise the server returns 404.

Request Headers

*   **[Content-Type](#content-type)**: `application/json-patch+json`

Status Codes

*   **204** - no content (success)
*   **400** - bad request
*   **404** - not found
*   **500** - server error

Example Request

```
PATCH /v1/data/servers HTTP/1.1Content-Type: application/json-patch+json
```

```
[  {    "op": "add",    "path": "-",    "value": {      "id": "s5",      "name": "job",      "protocols": ["amqp"],      "ports": ["p3"]    }  }]
```

Example Response

```
HTTP/1.1 204 No Content
```

### Delete a Document

```
DELETE /v1/data/{path:.+}
```

Delete a document.

The server processes the DELETE method as if the client had sent a PATCH request containing a single remove operation.

Query Parameters

*   **metrics** - Return performance metrics in addition to result. See [Performance Metrics](#performance-metrics) for more detail.

Status Codes

*   **204** - no content (success)
*   **404** - not found
*   **500** - server error

If the path refers to a non-existent document, the server returns 404.

Example Request

```
DELETE /v1/data/servers HTTP/1.1
```

Example Response

```
HTTP/1.1 204 No Content
```

## Query API

### Execute a Simple Query

```
POST /Content-Type: application/json
```

Execute a simple query.

OPA serves POST requests without a URL path by querying for the document at path `/data/system/main` by default. The content of that document defines the response entirely. This default can be overridden by the `default_decision` configuration. See the [Configuration Reference](/docs/configuration#miscellaneous) for more information.

Request Headers

*   **[Content-Type](#content-type)**: `application/json` or `application/yaml`

Query Parameters

*   **pretty** - If parameter is `true`, response will be formatted for humans.

Status Codes

*   **200** - no error
*   **400** - bad request
*   **404** - not found
*   **500** - server error

If the default decision (defaulting to `/system/main`) is undefined, the server returns 404.

The policy example below shows how to define a rule that will produce a value for the `/data/system/main` document. You can configure OPA to use a different URL path to serve these queries. See the [Configuration Reference](/docs/configuration) for more information.

The request message body is mapped to the [Input Document](/docs/philosophy#the-opa-document-model).

```
PUT /v1/policies/example1 HTTP/1.1Content-Type: text/plain
```

```
package systemmain := msg if {    msg := sprintf("hello, %v", [input.user])}
```

Example Request

```
POST /Content-Type: application/json
```

```
{  "user": ["alice"]}
```

Example Response

```
HTTP/1.1 200 OKContent-Type: application/json
```

```
"hello, alice"
```

### Execute an Ad hoc Query

Execute an ad hoc query and return bindings for variables found in the query.

```
GET /v1/query
```

Query Parameters

*   **q** - The ad hoc query to execute. OPA will parse, compile, and execute the query represented by the parameter value. The value MUST be URL encoded. Only used in GET method. For POST method the query is sent as part of the request body and this parameter is not used.
*   **pretty** - If parameter is `true`, response will be formatted for humans.
*   **explain** - Return query explanation in addition to result. Values: **notes**, **fails**, **full**, **debug**.
*   **metrics** - Return query performance metrics in addition to result. See [Performance Metrics](#performance-metrics) for more detail.

Status Codes

*   **200** - no error
*   **400** - bad request
*   **500** - server error
*   **501** - streaming not implemented

For queries that have large JSON values it is recommended to use the `POST` method with:

*   the query included as the request body
*   [Content-Type](#content-type): `application/json` request header

```
POST /v1/query HTTP/1.1Content-Type: application/json
```

```
{  "query": "input.servers[i].ports[_] = \"p2\"; input.servers[i].name = name",  "input": {    "servers": [ ... ],  }}
```

Example Request

```
GET /v1/query?q=data.servers[i].ports[_] = "p2"; data.servers[i].name = name HTTP/1.1
```

Example Response

```
HTTP/1.1 200 OKContent-Type: application/json
```

```
{  "result": [    {      "i": 3,      "name": "dev"    },    {      "i": 0,      "name": "app"    }  ]}
```

## Compile API

### Partially Evaluate a Query

```
POST /v1/compileContent-Type: application/json
```

Partially evaluate a query.

The [Compile API](#compile-api) allows you to partially evaluate Rego queries and obtain a simplified version of the policy. This is most useful when building integrations where policy logic is to be translated and evaluated in another environment. For example, [this post](https://blog.openpolicyagent.org/write-policy-in-opa-enforce-policy-in-sql-d9d24db93bf4) on the OPA blog shows how SQL can be generated based on Compile API output. For more details on Partial Evaluation in OPA, please refer to [this blog post](https://blog.openpolicyagent.org/partial-evaluation-162750eaf422).

Note that non-determinstic builtins (like `http.send`) are _not evaluated_ during PE. You can change that by providing `nondeterminsticBuiltins: true` in your payload options. This would be desirable when using PE for generating filters using extra information from `http.send`.

Request Body

Compile API requests contain the following fields:

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `query` | `string` | Yes | The query to partially evaluate and compile. |
| `input` | `any` | No | The input document to use during partial evaluation (default: undefined). |
| `options` | `object[string, any]` | No | Additional options to use during partial evaluation: `disableInlining` (default: undefined) and `nondeterminsticBuiltins` (default: false). |
| `unknowns` | `array[string]` | No | The terms to treat as unknown during partial evaluation (default: `["input"]`\]). |

Request Headers

*   **[Content-Type](#content-type)**: `application/json`
*   **[Content-Encoding](#content-encoding)**: `gzip`
*   **[Accept-Encoding](#accept-encoding)**: `gzip`

Query Parameters

*   **pretty** - If parameter is `true`, response will be formatted for humans.
*   **explain** - Return query explanation in addition to result. Values: **notes**, **fails**, **full**, **debug**.
*   **metrics** - Return query performance metrics in addition to result. See [Performance Metrics](#performance-metrics) for more detail.
*   **instrument** - Instrument query evaluation and return a superset of performance metrics in addition to result. See [Performance Metrics](#performance-metrics) for more detail.

Status Codes

*   **200** - no error
*   **400** - bad request
*   **500** - server error

The example below assumes that OPA has been given the following policy:

```
package exampleallow if {    input.subject.clearance_level >= data.reports[_].clearance_level}
```

Example Request

```
POST /v1/compile HTTP/1.1Content-Type: application/json
```

```
{  "query": "data.example.allow == true",  "input": {    "subject": {      "clearance_level": 4    }  },  "options": {    "disableInlining": []  },  "unknowns": [    "data.reports"  ]}
```

Example Response

```
HTTP/1.1 200 OKContent-Type: application/json
```

```
{  "result": {    "queries": [      [        {          "index": 0,          "terms": [            {              "type": "ref",              "value": [                {                  "type": "var",                  "value": "gte"                }              ]            },            {              "type": "number",              "value": 4            },            {              "type": "ref",              "value": [                {                  "type": "var",                  "value": "data"                },                {                  "type": "string",                  "value": "reports"                },                {                  "type": "var",                  "value": "i1"                },                {                  "type": "string",                  "value": "clearance_level"                }              ]            }          ]        }      ]    ]  }}
```

Unconditional Results from Partial Evaluation

When you partially evaluate a query with the Compile API, OPA returns a new set of queries and supporting policies. However, in some cases, the result of Partial Evaluation is a conclusive, unconditional answer.

For example, if you extend the policy above to include a "break glass" condition, the decision may be to allow all requests regardless of clearance level.

```
package exampleallow if {    input.subject.clearance_level >= data.reports[_].clearance_level}allow if {    data.break_glass = true}
```

In this case, if `data.break_glass` is `true` then the query `data.example.allow == true` will _always_ be true. If the query is always true, the `"queries"` value in the result will contain an empty array. The empty array indicates that your query can be satisfied without any further evaluation.

```
HTTP/1.1 200 OKContent-Type: application/json
```

```
{  "result": {    "queries": [      [],      [        {          "index": 0,          "terms": [            {              "type": "ref",              "value": [                {                  "type": "var",                  "value": "gte"                }              ]            },            {              "type": "number",              "value": 4            },            {              "type": "ref",              "value": [                {                  "type": "var",                  "value": "data"                },                {                  "type": "string",                  "value": "reports"                },                {                  "type": "var",                  "value": "$02"                },                {                  "type": "string",                  "value": "clearance_level"                }              ]            }          ]        }      ]    ]  }}
```

It is also possible for queries to _never_ be true. For example, the original policy could be extended to require that users be granted an exception:

```
package exampleallow if {    input.subject.clearance_level >= data.reports[_].clearance_level    exceptions[input.subject.name]}exceptions contains "bob"exceptions contains "alice"
```

In this case, if we execute query on behalf of a user that does not have an exception (e.g., `"eve"`), the OPA response will not contain a `queries` field at all. This indicates there are NO conditions that could make the query true.

```
HTTP/1.1 200 OKContent-Type: application/json
```

```
{  "result": {}}
```

The following table summarizes the behavior for partial evaluation results.

| Example Query | Unknowns | Result | Description |
| --- | --- | --- | --- |
| `input.x > 0` | `["input"]` | `{"result": {"queries": [[input.x > 0]]}}` | The query is partially evaluated and remaining conditions are returned. |
| `input.x > 0` | Not specified. | `{"result": {"queries": [[input.x > 0]]}}` | If the set of unknowns is not specified, it defaults to `["input"]`. |
| `input.x > 0` | `[]` | `{"result": {}}` | The query is false/undefined because there are no unknowns. |
| `1 > 0` | N/A | `{"result": {"queries": [[]]}}` | The query is always true. |
| `1 < 0` | N/A | `{"result": {}}` | The query is always false. |

> The partially evaluated queries are represented as strings in the table above. The actual API response contains the JSON AST representation.

### Compiling a Rego policy (and query) into data filters

```
POST /v1/compile/{path:.+}Content-Type: application/json
```

Where the `{path}` is the slash delimited filter rule to be compiled. E.g., to compile the `data.filters.include` rule, query `/v1/compile/filters/include`

Request Headers

| Name | Required | Accepted Values | Description |
| --- | --- | --- | --- |
| Content-Type | No | `application/json` | Indicates the request body is either a JSON encoded document. |
| Content-Encoding | No | gzip | Indicates the request body is a compressed gzip object. |
| Accept | Yes | See [below](#accept-header--controlling-the-target-response-format) | See [below](#accept-header--controlling-the-target-response-format) |

Accept Header – Controlling the Target Response Format

The same request can generate filters that are representable in many different ways, such as raw SQL `WHERE` clauses or Universal Conditions AST (UCAST).

OPA uses the `Accept` header to denote the target response format.

| Value | Response Schema | Description |
| --- | --- | --- |
| Multitarget: `application/vnd.opa.multitarget+json` | `result.{ucast,sqlserver,mysql,postgresql,sqlite}` | The partially evaluated result of the query in each target dialect. Use the `options.targetDialects` field in the request body to control targets. |
| UCAST: `application/vnd.opa.ucast.all+json`, `application/vnd.opa.ucast.minimal+json`, `application/vnd.opa.ucast.linq+json`, `application/vnd.opa.ucast.prisma+json` | `result.query` | UCAST JSON object describing the conditions under which the query is true. |
| SQL: `application/vnd.opa.sql.sqlserver+json`, `application/vnd.opa.sql.mysql+json`, `application/vnd.opa.sql.postgresql+json`, `application/vnd.opa.sql.sqlite+json` | `result.query` | String representing the SQL equivalent of the conditions under which the query is true. |

Request Body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `input` | `any` | No | The input document to use during partial evaluation and during mask rule evaluation (default: undefined). |
| `options` | `object[string, any]` | No | Additional options to use during partial evaluation |
| `options.disableInlining` | `array[string]` | No. Default: undefined | A list of rule references. |
| `options.maskRule` | `string` | No | The rule to evaluate for generating column masks. Overrides any `mask_rule` annotations defined in the policy. |
| `options.targetDialects` | `array[string]`, one of `ucast+all`, `ucast+minimal`, `ucast+prisma`, `ucast+linq`, `sql+sqlserver`, `sql+mysql`, `sql+postgresql` | Yes, if using `multitarget`. **Ignored for all other targets** | The output targets for partial evaluation. Different targets will have different constraints. Use [`Accept` header](#accept-header--controlling-the-target-response-format) to request a single compilation target. |
| `options.targetSQLTableMappings` | `object[string, object[string, string]]` | No | A mapping between tables and columns. See the [example](#example-mapping-table-and-column-names) for the schema. |
| `unknowns` | `array[string]` | No | The terms to treat as unknown during partial evaluation (default: `[]`). |

Example Request

With OPA running with this policy, we'll compile the query `data.filters.include` into SQL filters:

```
package filters# METADATA# scope: document# compile:#   unknowns: [input.fruits]include if input.fruits.name == input.favoriteinclude if {    input.fruits.name == "apple"    not input.favorite}
```

```
POST /v1/compile/filters/include HTTP/1.1Content-Type: application/jsonAccept: application/vnd.opa.sql.postgresql+json
```

```
{  "input": {    "favorite": "pineapple"  }}
```

Example Response

```
HTTP/1.1 200 OKContent-Type: application/vnd.opa.sql.postgresql+json
```

```
{  "result": {    "query": "WHERE fruits.name = E'pineapple'"  }}
```

Unconditional Results from Filters Generation

An absent `query` in the `result` indicates **unconditional deny**:

```
{  "result": {}}
```

An empty string `query` indicates **unconditional include**:

```
{  "result": {    "query": ""  }}
```

Example: Mapping Table and Column Names

For this example, let's assume OPA is running with this policy:

```
package filters# METADATA# scope: document# compile:#   unknowns: [input.fruits, input.price]include if input.fruits.name == input.favoriteinclude if input.price == "free"
```

If there is no one-to-one correspondence between unknowns and table/column names, the target mapping comes into play. With this mapping, we would translate the policy into `WHERE fruit.display_name = E'pineapple' AND fruit.price_tag = E'free'`:

```
POST /v1/compile/filters/includeContent-Type: application/jsonAccept: application/vnd.opa.sql.postgresql+json{  "input": {    "favorite": "pineapple"  },  "options": {    "targetSQLTableMappings": {      "postgresql": {        "fruits": {          "$self": "fruit",          "name": "display_name",          "price": "price_tag"        },        "price": {          "$table": "fruits"        }      }    }  }}
```

For multi-target requests, per-target replacements are possible, since the SQL table names might not match what you need for a UCAST consumer library.

## Health API

The `/health` API endpoint executes a simple built-in policy query to verify that the server is operational. Optionally it can account for bundle activation as well (useful for "ready" checks at startup).

### Query Parameters

*   `bundles` - Boolean parameter to account for bundle activation status in response. This includes any discovery bundles or bundles defined in the loaded discovery configuration.
*   `plugins` - Boolean parameter to account for plugin status in response.
*   `exclude-plugin` - String parameter to exclude a plugin from status checks. Can be added multiple times. Does nothing if `plugins` is not true. This parameter is useful for special use cases where a plugin depends on the server being fully initialized before it can fully initialize itself.

Status Codes

*   **200** - OPA service is healthy. If the `bundles` option is specified then all configured bundles have been activated. If the `plugins` option is specified then all plugins are in an OK state.
*   **500** - OPA service is not healthy. If the `bundles` option is specified this can mean any of the configured bundles have not yet been activated. If the `plugins` option is specified then at least one plugin is in a non-OK state.

info

The bundle activation check is only for initial bundle activation. Subsequent downloads will not affect the health check. The [Status](/docs/management-status) API should be used for more fine-grained bundle status monitoring.

Example Request

```
GET /health HTTP/1.1
```

Example Request (bundle activation)

```
GET /health?bundles HTTP/1.1
```

Example Request (plugin status)

```
GET /health?plugins HTTP/1.1
```

Example Request (plugin status with exclude)

```
GET /health?plugins&exclude-plugin=decision-logs&exclude-plugin=status HTTP/1.1
```

Healthy Response

```
HTTP/1.1 200 OKContent-Type: application/json
```

```
{}
```

Unhealthy Response

```
HTTP/1.1 500 Internal Server ErrorContent-Type: application/json
```

```
{  "error": "not all plugins in OK state"}
```

Other error messages include:

*   `"unable to perform evaluation"`
*   `"not all configured bundles have been activated"`

### Custom Health Checks

The Health API includes support for "all or nothing" checks that verify configured bundles have activated and plugins are operational. In some cases, health checks may need to perform fine-grained checks on plugin state or other internal components. To support these cases, use the policy-based Health API.

By convention, the `/health/live` and `/health/ready` API endpoints allow you to use Rego to evaluate the current state of the server and its plugins to determine "liveness" (when OPA is capable of receiving traffic) and "readiness" (when OPA is ready to receive traffic). Policy for the `live` and `ready` rules is defined under package `system.health`.

> The "liveness" and "readiness" check convention comes from [Kubernetes](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) but they are just conventions. You can implement your own check endpoints under the `system.health` package as needed. Any rules implemented inside `system.health` will be exposed at `/health/<rule-name>`.

Policy Examples

Here is a basic health policy for liveness and readiness. In this example, OPA is live once it is able to process the `live` rule. OPA is ready once all plugins have entered the OK state at least once.

```
package system.health# opa is live if it can process this ruledefault live := true# by default, opa is not readydefault ready := false# opa is ready once all plugins have reported OK at least onceready if {    input.plugins_ready}
```

Note that once `input.plugins_ready` is true, it stays true. If you want to fail the ready check when specific a plugin leaves the OK state, try this:

```
package system.healthdefault live := truedefault ready := false# opa is ready once all plugins have reported OK at least once AND# the bundle plugin is currently in an OK stateready if {    input.plugins_ready    input.plugin_state.bundle == "OK"}
```

See the following section for all the inputs available to use in health policy.

Policy Inputs

*   `input.plugins_ready`: Will be false until all registered plugins have started and are reporting an `OK` state, at which point it will be true. Once true, it will stay true until the process ends.
*   `input.plugin_state.<plugin_name>`: Shows the current state of a plugin, where `<plugin_name>` is replaced with the name of the plugin, e.g. `bundle`, `status`.

Status Codes

*   **200** - OPA service is healthy.
*   **500** - OPA service is not healthy because policy has not evaluated to true, or is missing.

Example Requests

```
GET /health/ready HTTP/1.1
```

```
GET /health/live HTTP/1.1
```

Healthy Response

```
HTTP/1.1 200 OKContent-Type: application/json
```

```
{}
```

Unhealthy Response

```
HTTP/1.1 500 Internal Server ErrorContent-Type: application/json
```

```
{  "error": "health policy was not true at data.system.health.<rule_name>"}
```

Other error messages include:

*   `"health policy was undefined at data.system.health.<rule_name>"`

## Config API

The `/config` API endpoint returns OPA's active configuration. When the discovery feature is enabled, this API can be used to fetch the discovered configuration in the last evaluated discovery bundle. The `credentials` field in the [Services](/docs/configuration#services) configuration and the `private_key` and `key` fields in the [Keys](/docs/configuration#keys) configuration will be omitted from the API response.

### Get Config

```
GET /v1/config HTTP/1.1
```

Query Parameters

*   **pretty** - If parameter is `true`, response will be formatted for humans.

Status Codes

*   **200** - no error
*   **500** - server error

Example Request

```
GET /v1/config HTTP/1.1
```

Example Response

```
HTTP/1.1 200 OKContent-Type: application/json
```

```
{  "result": {    "services": {      "acmecorp": {        "url": "https://example.com/control-plane-api/v1"      }    },    "labels": {      "id": "test-id",      "version": "0.27.0"    },    "keys": {      "global_key": {        "scope": "read"      }    },    "decision_logs": {      "service": "acmecorp"    },    "status": {      "service": "acmecorp"    },    "bundles": {      "authz": {        "service": "acmecorp"      }    },    "default_authorization_decision": "/system/authz/allow",    "default_decision": "/system/main"  }}
```

## Status API

The `/status` endpoint exposes a pull-based API for accessing OPA [Status](/docs/management-status) information. Normally this information is pushed by OPA to a remote service via HTTP, console, or custom plugins. However, in some cases, callers may wish to poll OPA and fetch the information.

### Get Status

```
GET /v1/status HTTP/1.1
```

Query Parameters

*   **pretty** - If parameter is `true`, response will be formatted for humans.

Status Codes

*   **200** - no error
*   **500** - server error

Example Request

```
GET /v1/status HTTP/1.1
```

Example Response

```
HTTP/1.1 200 OKContent-Type: application/json
```

```
{  "result": {    "labels": {      "id": "7da62ac6-42e0-4b3c-b6d5-199239ad436e",      "version": "99.9.9-dev"    },    "bundles": {      "play": {        "name": "play",        "active_revision": "b3BlbnBvbGljeWFnZW50Lm9yZw==",        "last_successful_activation": "2021-12-08T01:36:14.201927Z",        "last_successful_download": "2021-12-08T01:36:14.20038Z",        "last_successful_request": "2021-12-08T01:36:23.131346Z",        "last_request": "2021-12-08T01:36:23.131346Z",        "metrics": {          "timer_bundle_request_ns": 168273779        }      }    },    "metrics": {      "prometheus": {<------------------8<------------------>      }    },    "plugins": {      "bundle": {        "state": "OK"      },      "decision_logs": {        "state": "OK"      },      "discovery": {        "state": "OK"      },      "status": {        "state": "OK"      }    }  }}
```

## Authentication

The API is secured via [HTTPS, Authentication, and Authorization](/docs/security).

### Bearer Tokens

When OPA is started with the `--authentication=token` command line flag, clients MUST provide a Bearer token in the HTTP Authorization header:

```
GET /v1/data/exempli-gratia HTTP/1.1Authorization: Bearer my-secret-token
```

Bearer tokens must be represented with a valid HTTP header value character sequence.

OPA will extract the Bearer token value (which is set to `my-secret-token` above) and provide it to the authorization component inside OPA that will (i) validate the token and (ii) execute the authorization policy configured by the admin.

## Errors

All the API endpoints use standard HTTP status codes to indicate success or failure of an API call. If an API call fails, the response will contain a JSON encoded object that provides more detail. The `errors` and `location` fields are optional:

```
{  "code": "invalid_parameter",  "message": "error(s) occurred while compiling module(s)",  "errors": [    {      "code": "rego_unsafe_var_error",      "message": "var x is unsafe",      "location": {        "file": "example",        "row": 3,        "col": 1      }    }  ]}
```

### Method not Allowed

OPA will respond with a 405 Error (Method Not Allowed) if the method used to access the URL is not supported. For example, if a client uses the _HEAD_ method to access any path within `/v1/data/{path:.*}`, a 405 will be returned.

## Explanations

OPA supports query explanations that describe (in detail) the steps taken to produce query results.

Explanations can be requested for:

*   [Data API](#data-api) GET queries
*   [Query API](#query-api) queries

Explanations are requested by setting the `explain` query parameter to one of the following values:

*   **off** - do not return any trace.
*   **full** - returns a full query trace containing every step in the query evaluation process.
*   **debug** - returns a full query trace including debug info.
*   **notes** - returns only note events and their context.
*   **fails** - returns only fail events and their context.

By default, explanations are represented in a machine-friendly format. Set the `pretty` parameter to request a human-friendly format for debugging purposes.

### Trace Events

When the `explain` query parameter is set to anything except `off`, the response contains an array of Trace Event objects.

Trace Event objects contain the following fields:

*   `op` - identifies the kind of Trace Event. Values: `Enter`, `Exit`, `Eval`, `Fail`, `Redo`.
*   `query_id` - uniquely identifies the query that the Trace Event was emitted for.
*   `parent_id` - identifies the parent query.
*   `type` - indicates the type of the **node** field. Values: `expr`, `rule`, `body`.
*   `node` - contains the AST element associated with the evaluation step.
*   `locals` - contains the term bindings from the query at the time when the Trace Event was emitted.

Query IDs

Queries often reference rules or contain comprehensions. In both cases, query evaluation involves evaluation of one or more other queries, e.g., the body of the rule or comprehension.

Trace Events from different queries can be distinguished by the `query_id` field.

Trace Events from related queries can be identified by the `parent_id` field.

For example, if query A references a rule R, Trace Events emitted as part of evaluating rule R's body will have the `parent_id` field set to query A's `query_id`.

Types of Events

Each Trace Event represents a step in the query evaluation process. Trace Events are emitted at the following points:

*   **enter** - before a body or rule is evaluated.
*   **exit** - after a body or rule has evaluated successfully.
*   **eval** - before an expression is evaluated.
*   **fail** - after an expression has evaluated to false.
*   **redo** - before evaluation restarts from a body, rule, or expression.

By default, OPA searches for all sets of term bindings that make all expressions in the query evaluate to true. Because there may be multiple answers, the search can _restart_ when OPA determines the query is true or false. When the search restarts, a **Redo** Trace Event is emitted.

Example Trace Event

```
{  "op": "eval",  "query_id": 20,  "parent_id": 0,  "type": "expr",  "node": {    "index": 1,    "terms": [      {        "type": "var",        "value": "eq"      },      {        "type": "var",        "value": "x"      },      {        "type": "var",        "value": "y"      }    ]  },  "locals": [    {      "key": {        "type": "var",        "value": "x"      },      "value": {        "type": "string",        "value": "hello"      }    }  ]}
```

## Performance Metrics

OPA can report detailed performance metrics at runtime. Performance metrics can be requested on individual API calls and are returned inline with the API response. To enable performance metric collection on an API call, specify the `metrics=true` query parameter when executing the API call. Performance metrics are currently supported for the following APIs:

*   Policy API (PUT and DELETE)
*   Data API (GET, POST, PUT, and DELETE)
*   Query API (all methods)
*   Compile API (POST)

For example:

```
POST /v1/data/example?metrics=true HTTP/1.1
```

Response:

```
HTTP/1.1 200 OKContent-Type: application/json
```

```
{  "metrics": {    "timer_rego_query_compile_ns": 69994,    "timer_rego_query_eval_ns": 48425,    "timer_rego_query_parse_ns": 4096  },  "result": {    "some_strings": [      "hello",      "world"    ]  }}
```

OPA currently supports the following query performance metrics:

*   `timer_rego_input_parse_ns`: time taken (in nanoseconds) to parse the input
*   `timer_rego_query_parse_ns`: time taken (in nanoseconds) to parse the query.
*   `timer_rego_query_compile_ns`: time taken (in nanoseconds) to compile the query.
*   `timer_rego_query_eval_ns`: time taken (in nanoseconds) to evaluate the query.
*   `timer_rego_module_parse_ns`: time taken (in nanoseconds) to parse the input policy module.
*   `timer_rego_module_compile_ns`: time taken (in nanoseconds) to compile the loaded policy modules.
*   `timer_server_handler_ns`: time take (in nanoseconds) to handle the API request.
*   `counter_server_query_cache_hit`: number of cache hits for the query.

The `counter_server_query_cache_hit` counter gives an indication about whether OPA creates a new Rego query or it uses a pre-processed query which holds some prepared state to serve the API request. A pre-processed query will be faster to evaluate since OPA will not have to re-parse or compile it. Hence, when the query is served from the cache `timer_rego_query_parse_ns` and `timer_rego_query_compile_ns` timers will be omitted from the reported performance metrics.

OPA also supports query instrumentation. To enable query instrumentation, specify the `instrument=true` query parameter when executing the API call. Query instrumentation can help diagnose performance problems, however, it can add significant overhead to query evaluation. We recommend leaving query instrumentation off unless you are debugging a performance problem.

When instrumentation is enabled there are several additional performance metrics for the compilation stages. They follow the format of `timer_compile_stage_*_ns` and `timer_query_compile_stage_*_ns` for the query and module compilation stages.

## Provenance

OPA can report provenance information at runtime. Provenance information can be requested on individual API calls and are returned inline with the API response. To obtain provenance information on an API call, specify the `provenance=true` query parameter when executing the API call. Provenance information is currently supported for the following APIs:

*   Data API (GET and POST)

For example:

```
POST /v1/data/example?provenance=true HTTP/1.1
```

Response:

```
HTTP/1.1 200 OKContent-Type: application/json
```

```
{  "provenance": {    "build_commit": "1955fc4d",    "build_host": "foo.com",    "build_timestamp": "2019-04-29T23:42:04Z",    "bundles": {      "authz": {        "revision": "ID-b1298a6c-6ad8-11e9-a26f-d38b5ceadad5"      }    },    "version": "0.10.8-dev"  },  "result": true}
```

OPA currently supports the following query provenance information:

*   `version`: The version of this OPA instance.
*   `build_commit`: The git commit id of this OPA build.
*   `build_timestamp`: The timestamp when this instance was built.
*   `build_host`: The hostname where this instance was built.
*   `revision`: (Deprecated) The _revision_ string included in a .manifest file (if present) within a bundle. Omitted when `bundles` are configured.
*   `bundles`: A set of key-value pairs describing each bundle activated on the server. Includes the `revision` field which is the _revision_ string included in a .manifest file (if present) within a bundle

## Ecosystem Projects

Browse 17 projects related to "rest-api-integration" in the [OPA Ecosystem](/ecosystem/by-feature/rest-api-integration).