> ## 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

> Runs an ad-hoc OpalQuery and returns the results. Supports NODE queries (users, resources, groups) and ACCESS_PATH queries (principal-to-entitlement access edges). This endpoint is only available to our OpalQuery beta group. Please contact Opal support if you'd like to be added to the beta.



## 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: 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: owners
    description: Operations related to owners
  - name: requests
    description: Operations related to requests
  - name: resources
    description: Operations related to resources
  - name: paladin
    description: Operations related to Paladin
  - 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: >-
        Runs an ad-hoc OpalQuery and returns the results. Supports NODE queries
        (users, resources, groups) and ACCESS_PATH queries
        (principal-to-entitlement access edges). This endpoint is only available
        to our OpalQuery beta group. Please contact Opal support if you'd like
        to be added to the beta.
      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 running an ad-hoc OpalQuery. The `type` field
        determines which query schema applies.
      oneOf:
        - $ref: '#/components/schemas/OpalNodeQuery'
        - $ref: '#/components/schemas/OpalAccessPathQuery'
      discriminator:
        propertyName: type
        mapping:
          NODE:
            $ref: '#/components/schemas/OpalNodeQuery'
          ACCESS_PATH:
            $ref: '#/components/schemas/OpalAccessPathQuery'
    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/OpalAccessPathQueryResults'
      discriminator:
        propertyName: type
        mapping:
          NODE:
            $ref: '#/components/schemas/OpalNodeQueryResults'
          ACCESS_PATH:
            $ref: '#/components/schemas/OpalAccessPathQueryResults'
    OpalNodeQuery:
      type: object
      required:
        - type
      description: >-
        Request body for a NODE-type OpalQuery. Returns entities (users,
        resources, groups) matching the given filters.
      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
    OpalAccessPathQuery:
      type: object
      required:
        - type
      description: >-
        Request body for an ACCESS_PATH-type OpalQuery. Returns principal-to-
        entitlement access paths matching the given edge filters.
      example:
        type: ACCESS_PATH
        query:
          principalFilter:
            entityTypes:
              - USER
          entitlementFilter:
            entityItemTypes:
              - AWS_IAM_ROLE
          edgeFilter:
            directOnly: true
        first: 50
      properties:
        type:
          type: string
          enum:
            - ACCESS_PATH
        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_PATH response to fetch the next
            page of results.
        includeCount:
          type: boolean
          description: When true, populate totalCount in the response. Defaults to false.
          example: false
    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'
    OpalAccessPathQueryResults:
      type: object
      required:
        - type
        - edges
        - pageInfo
      description: >-
        Paginated results of an ACCESS_PATH-type OpalQuery — one edge per
        matched principal-to-entitlement access path.
      properties:
        type:
          type: string
          enum:
            - ACCESS_PATH
        edges:
          type: array
          description: List of matched access paths.
          items:
            $ref: '#/components/schemas/OpalAccessPathResultEdge'
        pageInfo:
          $ref: '#/components/schemas/PageInfo'
        totalCount:
          type: integer
          nullable: true
          description: >-
            Exact total number of matching paths when includeCount was true on
            the request; otherwise null.
    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_PATH 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
    OpalAccessPathResultEdge:
      type: object
      required:
        - node
        - cursor
      description: >-
        A single ACCESS_PATH result edge containing the matched path and its
        pagination cursor.
      properties:
        node:
          $ref: '#/components/schemas/OpalAccessPathResultNode'
        cursor:
          type: string
          description: Opaque cursor for this path, 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'
        entityTag:
          $ref: '#/components/schemas/EntityTagFilter'
        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'
    OpalAccessPathResultNode:
      type: object
      required:
        - principalId
        - entitlementId
        - depth
        - path
      description: A matched access path from an ACCESS_PATH OpalQuery.
      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 terminal access level.
        accessLevelName:
          type: string
          nullable: true
          description: Display name of the terminal access level.
        expiration:
          type: string
          format: date-time
          nullable: true
          description: Expiration of the terminal access, if any.
        depth:
          type: integer
          description: Number of hops from principal to entitlement (path length - 1).
        path:
          type: array
          description: Entity IDs along the path from principal to entitlement.
          items:
            type: string
            format: uuid
    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
        - 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
      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
    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 any value for the
            given key.
          example: platform
        connectionId:
          type: string
          format: uuid
          description: If specified, filters by tags associated with this connection.
    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.
    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

````