> ## Documentation Index
> Fetch the complete documentation index at: https://docs.opal.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Run an ad-hoc OpalQuery

> Executes an ad-hoc OpalQuery and returns paginated results. Two query types are supported: a **Node** query filters and returns entities (users, resources, or groups); an **Access** query returns the access grants between principals and their entitlements, one per (principal, entitlement, access level). Set `type` to `NODE` or `ACCESS` in the request body to select the query type.

This endpoint is available to OpalQuery beta participants. To request access, contact Opal support.




## OpenAPI

````yaml https://app.opal.dev/openapi.yaml post /queries/run
openapi: 3.1.0
info:
  contact:
    email: hello@opal.dev
    name: Opal Team
    url: https://www.opal.dev/
  description: >-
    The Opal API is a RESTful API that allows you to interact with the Opal
    Security platform programmatically.
  title: Opal API
  version: '1.0'
servers:
  - description: Production
    url: https://api.opal.dev/v1
security: []
tags:
  - name: access-rules
    description: Operations related to access rules
  - name: agent-activity
    description: Operations related to agent activity telemetry
  - name: apps
    description: Operations related to apps
  - name: bundles
    description: Operations related to bundles
  - name: campaigns
    description: Operations related to access review campaigns
  - name: configuration-templates
    description: Operations related to configuration templates
  - name: delegations
    description: Operations related to request reviewer delegations
  - name: event-streams
    description: Operations related to event streaming connections
  - name: events
    description: Operations related to events
  - name: groups
    description: Operations related to groups
  - name: group-bindings
    description: Operations related to group bindings
  - name: idp-group-mappings
    description: Operations related to IDP group mappings
  - name: message-channels
    description: Operations related to message channels
  - name: non-human-identities
    description: Operations related to non-human identities
  - name: on-call-schedules
    description: Operations related to on-call schedules
  - name: opal-queries
    description: Operations related to OpalQuery
  - name: opal-scripts
    description: Operations related to OpalScripts
  - name: owners
    description: Operations related to owners
  - name: requests
    description: Operations related to requests
  - name: resources
    description: Operations related to resources
  - name: role-assignments
    description: >-
      Operations related to role assignments (general grants between an entity
      and a principal)
  - name: paladin
    description: Operations related to Paladin
  - name: service-users
    description: Operations related to service users (non-human identities owned by a team)
  - name: sessions
    description: Operations related to sessions
  - name: tags
    description: Operations related to tags
  - name: tokens
    description: Operations related to API tokens
  - name: uars
    description: Operations related to UARs. Deprecated in favor of the `campaigns` API.
  - name: users
    description: Operations related to users
paths:
  /queries/run:
    post:
      tags:
        - opal-queries
      summary: Run an ad-hoc OpalQuery
      description: >
        Executes an ad-hoc OpalQuery and returns paginated results. Two query
        types are supported: a **Node** query filters and returns entities
        (users, resources, or groups); an **Access** query returns the access
        grants between principals and their entitlements, one per (principal,
        entitlement, access level). Set `type` to `NODE` or `ACCESS` in the
        request body to select the query type.


        This endpoint is available to OpalQuery beta participants. To request
        access, contact Opal support.
      operationId: runOpalQuery
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RunOpalQueryRequest'
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OpalQueryResults'
          description: The results of the OpalQuery.
      security:
        - BearerAuth: []
components:
  schemas:
    RunOpalQueryRequest:
      description: >
        Request body for an ad-hoc OpalQuery. Set `type` to `NODE` to query
        entities, or `ACCESS` to query access grants. The fields available in
        `query` differ by type — refer to each tab for the full schema.
      oneOf:
        - $ref: '#/components/schemas/OpalNodeQuery'
        - $ref: '#/components/schemas/OpalAccessQuery'
      discriminator:
        propertyName: type
        mapping:
          NODE: '#/components/schemas/OpalNodeQuery'
          ACCESS: '#/components/schemas/OpalAccessQuery'
    OpalQueryResults:
      description: >-
        Paginated results of an OpalQuery. The `type` field discriminates which
        result schema applies and mirrors the `type` field on the request.
      oneOf:
        - $ref: '#/components/schemas/OpalNodeQueryResults'
        - $ref: '#/components/schemas/OpalAccessQueryResults'
      discriminator:
        propertyName: type
        mapping:
          NODE: '#/components/schemas/OpalNodeQueryResults'
          ACCESS: '#/components/schemas/OpalAccessQueryResults'
    OpalNodeQuery:
      title: Node
      type: object
      required:
        - type
      description: >
        Use a Node query to retrieve entities — users, resources, or groups —
        that match a set of filters. You can filter by entity type, tags, and
        access relationships. Results are paginated and returned as a list of
        entity edges.
      example:
        type: NODE
        query:
          nodeFilters:
            entityTypes:
              - RESOURCE
            entityTag:
              key: env
              value: prod
          accessFilters:
            isAccessibleBy:
              entityTypes:
                - USER
              entityTag:
                key: contractor
        first: 50
      properties:
        type:
          type: string
          enum:
            - NODE
        query:
          $ref: '#/components/schemas/OpalNodeQueryBody'
        first:
          type: integer
          description: Maximum number of results to return. Defaults to 200.
          example: 200
        after:
          type: string
          description: Cursor from a previous response to fetch the next page of results.
          example: 29827fb8-f2dd-4e80-9576-28e31e9934ac
    OpalAccessQuery:
      title: Access
      type: object
      required:
        - type
      description: >
        Use an Access query to retrieve access grants between principals (users
        or groups) and their entitlements (resources or groups), with one result
        per (principal, entitlement, access level). Every access path reaching
        that grant is returned as metadata on the result. Uses the same filters
        as an Access Path query; results are paginated.
      example:
        type: ACCESS
        query:
          principalFilter:
            entityTypes:
              - USER
          entitlementFilter:
            entityItemTypes:
              - AWS_IAM_ROLE
        first: 50
      properties:
        type:
          type: string
          enum:
            - ACCESS
        query:
          $ref: '#/components/schemas/OpalAccessPathQueryBody'
        first:
          type: integer
          description: Maximum number of results to return. Defaults to 200.
          example: 200
        after:
          type: string
          description: >-
            Opaque cursor from a previous ACCESS response to fetch the next page
            of results.
    OpalNodeQueryResults:
      type: object
      required:
        - type
        - edges
        - pageInfo
      description: >-
        Paginated results of a NODE-type OpalQuery — one edge per matched entity
        (user, resource, or group).
      properties:
        type:
          type: string
          enum:
            - NODE
        edges:
          type: array
          description: List of matched entities.
          items:
            $ref: '#/components/schemas/OpalQueryResultEdge'
        pageInfo:
          $ref: '#/components/schemas/PageInfo'
    OpalAccessQueryResults:
      type: object
      required:
        - type
        - edges
        - pageInfo
      description: >-
        Paginated results of an ACCESS-type OpalQuery — one edge per matched
        (principal, entitlement, access level) grant.
      properties:
        type:
          type: string
          enum:
            - ACCESS
        edges:
          type: array
          description: List of matched access grants.
          items:
            $ref: '#/components/schemas/OpalAccessResultEdge'
        pageInfo:
          $ref: '#/components/schemas/PageInfo'
    OpalNodeQueryBody:
      type: object
      description: The filter body for a NODE-type OpalQuery.
      properties:
        nodeFilters:
          $ref: '#/components/schemas/AccessEntityFilters'
        accessFilters:
          $ref: '#/components/schemas/AccessRelationshipFilters'
    OpalAccessPathQueryBody:
      type: object
      description: >-
        Edge-query filters for an ACCESS OpalQuery. At least one of
        principalFilter or entitlementFilter is required.
      properties:
        principalFilter:
          $ref: '#/components/schemas/AccessEntityFilters'
        entitlementFilter:
          $ref: '#/components/schemas/AccessEntityFilters'
        principalAccessFilters:
          $ref: '#/components/schemas/AccessRelationshipFilters'
          description: >
            Advanced access filter on the principal side of each path. Restricts
            results to principals that additionally satisfy these access-edge
            constraints: `hasAccessTo` keeps only principals that also have
            access to a matching entity; `isAccessibleBy` keeps only principals
            that are also accessible by a matching entity. Only takes effect
            when `principalFilter` is also supplied (it refines that filter); on
            its own it has no effect.
        entitlementAccessFilters:
          $ref: '#/components/schemas/AccessRelationshipFilters'
          description: >
            Advanced access filter on the entitlement side of each path.
            Restricts results to entitlements that additionally satisfy these
            access-edge constraints: `hasAccessTo` keeps only entitlements that
            also have access to a matching entity; `isAccessibleBy` keeps only
            entitlements that are also accessible by a matching entity. Only
            takes effect when `entitlementFilter` is also supplied (it refines
            that filter); on its own it has no effect.
        accessLevelRemoteIds:
          type: array
          description: Filter by access-level remote IDs on the terminal edge.
          items:
            type: string
        accessLevelNames:
          type: array
          description: Filter by access-level display names on the terminal edge.
          items:
            type: string
        edgeFilter:
          $ref: '#/components/schemas/OpalAccessPathEdgeFilter'
    OpalQueryResultEdge:
      type: object
      required:
        - node
        - cursor
      description: >-
        A single result edge from an OpalQuery, containing the matched entity
        and its pagination cursor.
      properties:
        node:
          $ref: '#/components/schemas/OpalQueryResultNode'
        cursor:
          type: string
          description: Opaque cursor for this entity, used for pagination.
    PageInfo:
      type: object
      required:
        - hasNextPage
        - endCursor
        - hasPreviousPage
        - startCursor
      properties:
        hasNextPage:
          type: boolean
          description: Whether there are more items after the end cursor
        endCursor:
          type: string
          description: The cursor to continue pagination forwards
        hasPreviousPage:
          type: boolean
          description: Whether there are more items before the start cursor
        startCursor:
          type: string
          description: The cursor to continue pagination backwards
    OpalAccessResultEdge:
      type: object
      required:
        - node
        - cursor
      description: >-
        A single ACCESS result edge containing the matched access grant and its
        pagination cursor.
      properties:
        node:
          $ref: '#/components/schemas/OpalAccessResultNode'
        cursor:
          type: string
          description: Opaque cursor for this grant, used for pagination.
    AccessEntityFilters:
      type: object
      description: >-
        Filters for matching entities by type, name, tag, IDs, connections, or
        access levels. Supports recursive logical composition via allOf/anyOf.
      properties:
        entityTypes:
          type: array
          description: >-
            Filter by entity type. Only RESOURCE, GROUP, and USER are queryable
            via OpalQuery.
          items:
            type: string
            enum:
              - RESOURCE
              - GROUP
              - USER
        entityItemTypes:
          type: array
          description: Filter by entity item types.
          items:
            $ref: '#/components/schemas/EntityItemTypeEnum'
        entityName:
          $ref: '#/components/schemas/EntityNameFilter'
        entityDescription:
          $ref: '#/components/schemas/EntityDescriptionFilter'
        entityTag:
          $ref: '#/components/schemas/EntityTagFilter'
        entityTagKey:
          $ref: '#/components/schemas/EntityTagKeyFilter'
        hrIdpStatus:
          $ref: '#/components/schemas/IdpStatusFilter'
        entityAdminOwner:
          $ref: '#/components/schemas/EntityAdminFilter'
        entityIDs:
          type: array
          description: Filter by specific entity UUIDs.
          items:
            type: string
            format: uuid
        importedFromApp:
          type: array
          description: Filter by app IDs from which returned nodes will be imported from.
          items:
            type: string
            format: uuid
        roleRemoteIds:
          type: array
          description: >-
            Filter by role remote IDs. Can only be applied within a hasAccessTo
            clause.
          items:
            type: string
        roleNames:
          type: array
          description: >-
            Filter by role display names (e.g. "Admin", "Read"). Can only be
            applied within a hasAccessTo clause.
          items:
            type: string
        allOf:
          type: array
          description: |
            A list of nested filters that must all match (logical AND). Each
             item has the same shape as this object — scalar fields like
             `entityTypes` or `entityTag`, and can further nest `allOf`,
             `anyOf`, or `not`.
          items:
            $ref: '#/components/schemas/AccessEntityFilters'
        anyOf:
          type: array
          description: |
            A list of nested filters where at least one must match (logical
             OR). Each item has the same shape as this object.
          items:
            $ref: '#/components/schemas/AccessEntityFilters'
        not:
          description: >
            Excludes entities matching the embedded filter (logical NOT). Pass a
            filter object with the same shape as this one — typically a single
            scalar field, like `{not: {entityTypes: ["RESOURCE"]}}` to exclude
            resources.
          type: object
          x-go-type: AccessEntityFilters
    AccessRelationshipFilters:
      type: object
      description: >
        Filters the returned nodes by the access edges connected to them. When
        `isAccessibleBy` and `hasAccessTo` are provided, the returned nodes must
        satisfy both edge constraints simultaneously.
      properties:
        isAccessibleBy:
          $ref: '#/components/schemas/AccessEntityFilters'
          description: >-
            Inbound-edge filter. The returned node must be accessible by at
            least one entity matching this filter.
        hasAccessTo:
          $ref: '#/components/schemas/AccessEntityFilters'
          description: >-
            Outbound-edge filter. The returned node must have access to at least
            one entity matching this filter.
    OpalAccessPathEdgeFilter:
      type: object
      description: Constraints on the access path edges themselves.
      properties:
        directOnly:
          type: boolean
          description: >-
            When true, only return direct (depth-1) principal-to-entitlement
            edges.
          example: true
        accessDurationType:
          type: string
          description: Constrain results by whether the terminal access expires.
          enum:
            - EXPIRING_ONLY
            - PERMANENT_ONLY
          example: EXPIRING_ONLY
    OpalQueryResultNode:
      type: object
      required:
        - id
        - name
        - entityType
        - entityItemType
      description: A matched entity from an OpalQuery result.
      properties:
        id:
          type: string
          format: uuid
          description: The entity's unique identifier.
        name:
          type: string
          description: The display name of the entity.
        entityType:
          type: string
          enum:
            - USER
            - GROUP
            - RESOURCE
          description: The top-level entity type.
        entityItemType:
          $ref: '#/components/schemas/EntityItemTypeEnum'
    OpalAccessResultNode:
      type: object
      required:
        - principalId
        - entitlementId
        - isDirect
        - paths
      description: >-
        A matched access grant from an ACCESS OpalQuery — one per (principal,
        entitlement, access level), with every access path as metadata.
      properties:
        principalId:
          type: string
          format: uuid
          description: The principal entity ID.
        entitlementId:
          type: string
          format: uuid
          description: The entitlement entity ID.
        accessLevelRemoteId:
          type: string
          nullable: true
          description: Remote ID of the access level.
        accessLevelName:
          type: string
          nullable: true
          description: Display name of the access level.
        effectiveExpiration:
          type: string
          format: date-time
          nullable: true
          description: >-
            The expiration in effect across all paths (the latest-expiring; a
            permanent path wins). Null means access never expires.
        isDirect:
          type: boolean
          description: True when any path is a direct grant.
        paths:
          type: array
          description: Every access path reaching this grant.
          items:
            $ref: '#/components/schemas/OpalAccessPathDetail'
    EntityItemTypeEnum:
      description: Granular subtype of an entity.
      enum:
        - USER
        - SERVICE_USER
        - ACTIVE_DIRECTORY_GROUP
        - AWS_SSO_GROUP
        - DUO_GROUP
        - GIT_HUB_TEAM
        - GIT_LAB_GROUP
        - GOOGLE_GROUPS_GROUP
        - GOOGLE_GROUPS_GKE_GROUP
        - LDAP_GROUP
        - OKTA_GROUP
        - OKTA_GROUP_RULE
        - TAILSCALE_GROUP
        - TWINGATE_GROUP
        - TWINGATE_GROUP_SYNCED
        - OPAL_GROUP
        - OPAL_ACCESS_RULE
        - AZURE_AD_SECURITY_GROUP
        - AZURE_AD_MICROSOFT_365_GROUP
        - CONNECTOR_GROUP
        - SNOWFLAKE_ROLE
        - WORKDAY_USER_SECURITY_GROUP
        - DATABRICKS_ACCOUNT_GROUP
        - AWS_IAM_ROLE
        - AWS_EC2_INSTANCE
        - AWS_EKS_CLUSTER
        - AWS_RDS_POSTGRES_INSTANCE
        - AWS_RDS_POSTGRES_CLUSTER
        - AWS_RDS_MYSQL_INSTANCE
        - AWS_RDS_MYSQL_CLUSTER
        - AWS_ACCOUNT
        - AWS_SSO_PERMISSION_SET
        - AWS_AGENTCORE_GATEWAY
        - AWS_AGENTCORE_GATEWAY_TARGET
        - AWS_AGENTCORE_GATEWAY_TOOL
        - AZURE_MANAGEMENT_GROUP
        - AZURE_RESOURCE_GROUP
        - AZURE_SUBSCRIPTION
        - AZURE_VIRTUAL_MACHINE
        - AZURE_STORAGE_ACCOUNT
        - AZURE_STORAGE_CONTAINER
        - AZURE_SQL_SERVER
        - AZURE_SQL_MANAGED_INSTANCE
        - AZURE_SQL_DATABASE
        - AZURE_SQL_MANAGED_DATABASE
        - AZURE_USER_ASSIGNED_MANAGED_Identity
        - AZURE_ENTRA_ID_ROLE
        - AZURE_ENTERPRISE_APP
        - CUSTOM
        - CUSTOM_CONNECTOR
        - GCP_ORGANIZATION
        - GCP_BUCKET
        - GCP_COMPUTE_INSTANCE
        - GCP_BIG_QUERY_DATASET
        - GCP_BIG_QUERY_TABLE
        - GCP_FOLDER
        - GCP_GKE_CLUSTER
        - GCP_PROJECT
        - GCP_CLOUD_SQL_POSTGRES_INSTANCE
        - GCP_CLOUD_SQL_MYSQL_INSTANCE
        - GCP_SERVICE_ACCOUNT
        - GCP_BILLING_ACCOUNT
        - GIT_HUB_REPO
        - GIT_HUB_ORG_ROLE
        - GIT_LAB_PROJECT
        - GOOGLE_WORKSPACE_ROLE
        - MONGO_INSTANCE
        - MONGO_ATLAS_INSTANCE
        - OKTA_APP
        - OKTA_ROLE
        - OPAL_ROLE
        - OPAL_SCOPED_ROLE
        - PAGERDUTY_ROLE
        - TAILSCALE_SSH
        - TWINGATE_RESOURCE
        - SALESFORCE_PERMISSION_SET
        - SALESFORCE_PROFILE
        - SALESFORCE_ROLE
        - SNOWFLAKE_DATABASE
        - SNOWFLAKE_SCHEMA
        - SNOWFLAKE_TABLE
        - WORKDAY_ROLE
        - MYSQL_INSTANCE
        - MARIADB_INSTANCE
        - POSTGRES_INSTANCE
        - TELEPORT_ROLE
        - DATABRICKS_ACCOUNT_SERVICE_PRINCIPAL
        - ILEVEL_ADVANCED_ROLE
        - DATABRICKS_CATALOG
        - DATABRICKS_SCHEMA
        - DATABRICKS_VOLUME
        - DATABRICKS_FUNCTION
        - DATABRICKS_MODEL
        - DATABRICKS_SERVICE
        - DATABRICKS_MCP_SERVER
      example: OPAL_ROLE
      type: string
    EntityNameFilter:
      type: object
      required:
        - stringMatchType
        - string
      description: Filters entities by name using a string match strategy.
      properties:
        stringMatchType:
          $ref: '#/components/schemas/StringMatchType'
        string:
          type: string
          description: The string value to match against the entity name.
          example: engineering
    EntityDescriptionFilter:
      type: object
      required:
        - string
      description: >
        Filters GROUP and RESOURCE entities by a case-insensitive substring of
        their description ("contains"). USER entities have no description and
        never match, in either polarity. `not` inverts the match within the
        resource/group domain ("does NOT contain"), so it still returns only
        resources/groups rather than sweeping in users.
      properties:
        string:
          type: string
          description: The substring to match against the entity description.
          example: production
        not:
          type: boolean
          description: >-
            Invert the match — return resources/groups whose description does
            NOT contain the substring.
    EntityTagFilter:
      type: object
      required:
        - key
      description: >-
        Filters entities by a tag key/value pair, optionally scoped to a
        connection.
      properties:
        key:
          type: string
          description: The tag key to filter by.
          example: team
        value:
          type: string
          description: >-
            The tag value to filter by. If omitted, matches only tags with no
            value; use entityTagKey to match any value for a key.
          example: platform
        connectionId:
          type: string
          format: uuid
          description: If specified, filters by tags associated with this connection.
    EntityTagKeyFilter:
      type: object
      required:
        - keys
      description: >
        Filters entities that have a tag whose key is one of `keys`, whatever
        its value (including no value). Keys match exactly and case-sensitively.
        An empty list matches nothing. AGENT entities carry no tags, so they
        never match; under `not`, every agent matches, as with entityTag.
      properties:
        keys:
          type: array
          description: The tag keys to match.
          items:
            type: string
          example:
            - Critical
    IdpStatusFilter:
      type: object
      description: >
        Filters USER entities by their HR/IDP lifecycle status. Only applies to
        USER entities; GROUP and RESOURCE entities never match, in either
        polarity. `statuses` combine with OR. `not` inverts the match within the
        user domain (e.g. "IDP status is NOT active"), so it still returns only
        users rather than sweeping in groups/resources.
      properties:
        statuses:
          type: array
          description: Match users whose HR/IDP status is one of these values.
          items:
            $ref: '#/components/schemas/UserHrIdpStatusEnum'
        not:
          type: boolean
          description: >-
            Invert the match within the user domain (e.g. "IDP status is NOT
            active").
    EntityAdminFilter:
      type: object
      required:
        - ownerIDs
      description: >
        Filters GROUP and RESOURCE entities by their admin owner. USER entities
        never match, in either polarity. `not` inverts the match within the
        resource/group domain (self-negating, like IdpStatusFilter): omit it (or
        false) to include entities owned by the given owners, set it true to
        exclude them.
      properties:
        ownerIDs:
          type: array
          description: The owner (group) UUIDs to match entities against.
          items:
            type: string
            format: uuid
        not:
          type: boolean
          description: >-
            Invert the match — return resources/groups NOT owned by the given
            owners.
    OpalAccessPathDetail:
      type: object
      required:
        - path
      description: A single access path within an ACCESS result.
      properties:
        path:
          type: array
          description: Entity IDs along the path from principal to entitlement.
          items:
            type: string
            format: uuid
        expiration:
          type: string
          format: date-time
          nullable: true
          description: This path's expiration, if any.
    StringMatchType:
      type: string
      description: >-
        How to match a string value against entity names. REGEX matches the
        value as a case-insensitive regular expression.
      enum:
        - CONTAINS
        - EQUALS
        - STARTS_WITH
        - ENDS_WITH
        - REGEX
    UserHrIdpStatusEnum:
      description: User status pulled from an HR/IDP provider.
      enum:
        - ACTIVE
        - SUSPENDED
        - DEPROVISIONED
        - DELETED
        - NOT_FOUND
      example: ACTIVE
      type: string
  securitySchemes:
    BearerAuth:
      scheme: bearer
      type: http

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.