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

# Check that an expression compiles

> Compiles an expression without touching cost data, for checking a rule as it is typed. Returns the compiler error when it does not compile. Use preview to find out what it would match. A rule is written one of three ways and exactly one may be sent: expression as CostQL text, clause as a single chip, or node as a tree of chips. A node is rendered server-side by the same renderer the decompose endpoint round-trips through, so a rule saved from chips reads back as the identical tree, and sending node together with expression or clause is a 400 rather than a silent pick. Every leaf of a node is checked like a flat clause, so a tree cannot smuggle in a field or operator the clause path would refuse. Send key as well and the response also reports whether an existing literal rule with no validity window under that tag key (matched case-insensitively) already carries the same predicate, returning its id; the match is on a canonical fingerprint, so a reordered restatement of the same predicate is reported as a duplicate. The response also carries expression_hash, that same canonical fingerprint of the expression that was checked, so a caller can compare two expressions for semantic equality without canonicalising them itself.



## OpenAPI

````yaml /api-reference/costgraph/openapi.json post /api/v1/tenant/virtual-tags/validate
openapi: 3.0.0
info:
  description: Read and manage your CostGraph organization, spend, alerts, and settings.
  title: CostGraph API
  contact: {}
  version: '1.0'
servers:
  - url: https://api.costgraph.ai
security: []
tags:
  - name: ai
    x-group: AI
  - name: ai-serving
    x-group: AI serving
  - name: anomalies
    x-group: Anomalies
  - name: auth
    x-group: Auth
  - name: billing
    x-group: Billing
  - name: billing-export
    x-group: Billing export
  - name: budgets
    x-group: Budgets
  - name: ci
    x-group: CI
  - name: compute-recommendations
    x-group: Compute recommendations
  - name: config
    x-group: Config
  - name: cost
    x-group: Cost
  - name: gpus
    x-group: GPUs
  - name: graphai
    x-group: Graph AI
  - name: infracost
    x-group: Infracost
  - name: integrations
    x-group: Integrations
  - name: invitations
    x-group: Invitations
  - name: kubernetes-clusters
    x-group: Kubernetes clusters
  - name: marketplace
    x-group: Marketplace
  - name: network-requests
    x-group: Network requests
  - name: notifications
    x-group: Notifications
  - name: oauth
    x-group: OAuth
  - name: oauth-clients
    x-group: OAuth clients
  - name: opencost
    x-group: OpenCost
  - name: organization
    x-group: Audit log
  - name: organizations
    x-group: Organizations
  - name: placement-alternatives
    x-group: Placement alternatives
  - name: reports
    x-group: Reports
  - name: service-map
    x-group: Service map
  - name: settings
    x-group: Settings
  - name: sso
    x-group: Single sign-on
  - name: tenants
    x-group: Tenants
  - name: user
    x-group: Users
  - name: virtual-machines
    x-group: Virtual machines
  - name: virtual-tags
    x-group: Virtual tags
  - name: workflows
    x-group: Workflows
paths:
  /api/v1/tenant/virtual-tags/validate:
    post:
      tags:
        - virtual-tags
      summary: Check that an expression compiles
      description: >-
        Compiles an expression without touching cost data, for checking a rule
        as it is typed. Returns the compiler error when it does not compile. Use
        preview to find out what it would match. A rule is written one of three
        ways and exactly one may be sent: expression as CostQL text, clause as a
        single chip, or node as a tree of chips. A node is rendered server-side
        by the same renderer the decompose endpoint round-trips through, so a
        rule saved from chips reads back as the identical tree, and sending node
        together with expression or clause is a 400 rather than a silent pick.
        Every leaf of a node is checked like a flat clause, so a tree cannot
        smuggle in a field or operator the clause path would refuse. Send key as
        well and the response also reports whether an existing literal rule with
        no validity window under that tag key (matched case-insensitively)
        already carries the same predicate, returning its id; the match is on a
        canonical fingerprint, so a reordered restatement of the same predicate
        is reported as a duplicate. The response also carries expression_hash,
        that same canonical fingerprint of the expression that was checked, so a
        caller can compare two expressions for semantic equality without
        canonicalising them itself.
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/virtualtag.ValidateRequest'
        description: >-
          Expression to check, or a clause or node to build one from; set yields
          to value for an inherited rule's value expression, and key to also
          check the predicate is not already taken under that tag key
        required: true
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/responses.SuccessResponse'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/virtualtag.ValidateResult'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/responses.ErrorResponse'
        '500':
          description: Internal Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/responses.ErrorResponse'
      security:
        - BearerAuth: []
components:
  schemas:
    virtualtag.ValidateRequest:
      type: object
      properties:
        clause:
          $ref: '#/components/schemas/virtualtag.Clause'
        expression:
          type: string
        key:
          type: string
        node:
          $ref: '#/components/schemas/virtualtag.Node'
        scope:
          type: string
        yields:
          type: string
    responses.SuccessResponse:
      type: object
      required:
        - message
        - status
      properties:
        data: {}
        message:
          type: string
          example: some message
        status:
          type: string
          example: success
    virtualtag.ValidateResult:
      type: object
      properties:
        duplicate:
          type: boolean
        duplicate_rule_id:
          type: string
        expression_hash:
          type: string
    responses.ErrorResponse:
      type: object
      required:
        - message
        - status
      properties:
        message:
          type: string
          example: some message
        status:
          type: string
          example: error
    virtualtag.Clause:
      type: object
      properties:
        field:
          type: string
        match_value:
          type: string
        operator:
          type: string
    virtualtag.Node:
      type: object
      properties:
        children:
          type: array
          items:
            $ref: '#/components/schemas/virtualtag.Node'
        clause:
          $ref: '#/components/schemas/virtualtag.Clause'
        kind:
          type: string
  securitySchemes:
    BearerAuth:
      description: Enter "Bearer {token}"
      type: apiKey
      name: Authorization
      in: header

````

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