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

# Create report

> Create a report from a complete definition.



## OpenAPI

````yaml /docs/api/openapi/report_openapi.json post /core.v1.ReportService/CreateReport
openapi: 3.1.0
info:
  title: core.v1.ReportService
  version: 0.0.1
servers:
  - url: https://api.joinformal.com
    description: Production API
security: []
tags:
  - name: core.v1.ReportService
    description: >-
      ReportService manages reports: grids of widgets over the organization's
      logs and AI usage.
       A report's definition holds its whole layout and every widget, so one call builds a report,
       one call replaces it, and getting a report then creating one with its definition clones it.
paths:
  /core.v1.ReportService/CreateReport:
    post:
      tags:
        - core.v1.ReportService
      summary: Create report
      description: Create a report from a complete definition.
      operationId: core.v1.ReportService.CreateReport
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/core.v1.CreateReportRequest'
        required: true
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/core.v1.CreateReportResponse'
        '400':
          description: Bad Request - Invalid request parameters or body
          content:
            application/json:
              schema:
                type: object
                properties:
                  code:
                    type: string
                    example: invalid_request
                  message:
                    type: string
                    example: Invalid request parameters
                  details:
                    type: object
        '401':
          description: Unauthorized - Missing or invalid authentication
          content:
            application/json:
              schema:
                type: object
                properties:
                  code:
                    type: string
                    example: unauthorized
                  message:
                    type: string
                    example: Authentication required
        '403':
          description: Forbidden - Insufficient permissions
          content:
            application/json:
              schema:
                type: object
                properties:
                  code:
                    type: string
                    example: forbidden
                  message:
                    type: string
                    example: Insufficient permissions to perform this action
        '404':
          description: Not Found - Resource does not exist
          content:
            application/json:
              schema:
                type: object
                properties:
                  code:
                    type: string
                    example: not_found
                  message:
                    type: string
                    example: Resource not found
        '500':
          description: Internal Server Error - An error occurred processing the request
          content:
            application/json:
              schema:
                type: object
                properties:
                  code:
                    type: string
                    example: internal_error
                  message:
                    type: string
                    example: An internal error occurred
      security:
        - ApiKeyAuth: []
      x-codeSamples:
        - lang: curl
          label: cURL
          source: >-
            curl -X POST
            "https://api.joinformal.com/core.v1.ReportService/CreateReport" \
              -H "X-API-KEY: YOUR_API_KEY" \
              -H "Content-Type: application/json" \
              -d '{
                "example": "value"
              }'
        - lang: javascript
          label: JavaScript (fetch)
          source: >-
            fetch("https://api.joinformal.com/core.v1.ReportService/CreateReport",
            {
              method: "POST",
              headers: {
                "X-API-KEY": "YOUR_API_KEY",
                "Content-Type": "application/json"
              },
              body: JSON.stringify({
                example: "value"
              })
            })
              .then(response => response.json())
              .then(data => console.log(data))
              .catch(error => console.error(error));
        - lang: python
          label: Python
          source: >-
            import requests


            url =
            "https://api.joinformal.com/core.v1.ReportService/CreateReport"

            headers = {
                "X-API-KEY": "YOUR_API_KEY",
                "Content-Type": "application/json"
            }

            data = {
                "example": "value"
            }


            response = requests.post(url, headers=headers, json=data)

            print(response.json())
        - lang: go
          label: Go
          source: |-
            package main

            import (
                "bytes"
                "encoding/json"
                "fmt"
                "io"
                "net/http"
            )

            func main() {
                url := "https://api.joinformal.com/core.v1.ReportService/CreateReport"

                body := map[string]string{
                    "example": "value",
                }

                jsonData, _ := json.Marshal(body)

                req, _ := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
                req.Header.Set("X-API-KEY", "YOUR_API_KEY")
                req.Header.Set("Content-Type", "application/json")

                client := &http.Client{}
                resp, err := client.Do(req)
                if err != nil {
                    panic(err)
                }
                defer resp.Body.Close()

                responseBody, _ := io.ReadAll(resp.Body)
                fmt.Println(string(responseBody))
            }
components:
  schemas:
    core.v1.CreateReportRequest:
      type: object
      properties:
        name:
          type: string
          title: name
          maxLength: 200
          minLength: 1
        description:
          type: string
          title: description
          maxLength: 2000
        definition:
          $ref: '#/components/schemas/core.v1.ReportDefinition'
          title: definition
      title: CreateReportRequest
      required:
        - definition
      additionalProperties: false
    core.v1.CreateReportResponse:
      type: object
      properties:
        report:
          $ref: '#/components/schemas/core.v1.Report'
          title: report
      title: CreateReportResponse
      additionalProperties: false
    core.v1.ReportDefinition:
      type: object
      properties:
        layout:
          $ref: '#/components/schemas/core.v1.ReportLayout'
          title: layout
        defaultTimeRange:
          $ref: '#/components/schemas/core.v1.ReportTimeRange'
          title: default_time_range
        widgets:
          type: array
          items:
            $ref: '#/components/schemas/core.v1.ReportWidget'
          title: widgets
          maxItems: 50
      title: ReportDefinition
      required:
        - layout
      additionalProperties: false
      description: >-
        report_definition.span_within_columns // a widget's span must not exceed
        the report's columns

        report_definition.unique_keys // widget keys must be unique within a
        report
    core.v1.Report:
      type: object
      properties:
        id:
          type: string
          title: id
        name:
          type: string
          title: name
        description:
          type: string
          title: description
        definition:
          $ref: '#/components/schemas/core.v1.ReportDefinition'
          title: definition
        createdAt:
          $ref: '#/components/schemas/google.protobuf.Timestamp'
          title: created_at
        updatedAt:
          $ref: '#/components/schemas/google.protobuf.Timestamp'
          title: updated_at
      title: Report
      additionalProperties: false
    core.v1.ReportLayout:
      type: object
      properties:
        columns:
          type: integer
          title: columns
          maximum: 3
          minimum: 1
          format: int32
      title: ReportLayout
      additionalProperties: false
    core.v1.ReportTimeRange:
      type: string
      title: ReportTimeRange
      enum:
        - REPORT_TIME_RANGE_UNSPECIFIED
        - REPORT_TIME_RANGE_7_DAYS
        - REPORT_TIME_RANGE_30_DAYS
        - REPORT_TIME_RANGE_90_DAYS
    core.v1.ReportWidget:
      type: object
      properties:
        key:
          type: string
          title: key
          maxLength: 64
          pattern: ^([a-z0-9][a-z0-9-]*)?$
        title:
          type: string
          title: title
          maxLength: 200
        description:
          type: string
          title: description
          maxLength: 1000
        layout:
          $ref: '#/components/schemas/core.v1.ReportWidgetLayout'
          title: layout
        aiUsage:
          $ref: '#/components/schemas/core.v1.ReportAIUsageWidget'
          title: ai_usage
          description: One of the discriminated union fields - use exactly one
        logs:
          $ref: '#/components/schemas/core.v1.ReportLogsWidget'
          title: logs
          description: One of the discriminated union fields - use exactly one
        note:
          $ref: '#/components/schemas/core.v1.ReportNoteWidget'
          title: note
          description: One of the discriminated union fields - use exactly one
      title: ReportWidget
      additionalProperties: false
      description: 'Exactly one of these fields is required: ai_usage or logs or note.'
    google.protobuf.Timestamp:
      type: string
      examples:
        - '2023-01-15T01:30:15.01Z'
        - '2024-12-25T12:00:00Z'
      format: date-time
      description: >-
        A Timestamp represents a point in time independent of any time zone or
        local
         calendar, encoded as a count of seconds and fractions of seconds at
         nanosecond resolution. The count is relative to an epoch at UTC midnight on
         January 1, 1970, in the proleptic Gregorian calendar which extends the
         Gregorian calendar backwards to year one.

         All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap
         second table is needed for interpretation, using a [24-hour linear
         smear](https://developers.google.com/time/smear).

         The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By
         restricting to that range, we ensure that we can convert to and from [RFC
         3339](https://www.ietf.org/rfc/rfc3339.txt) date strings.

         # Examples

         Example 1: Compute Timestamp from POSIX `time()`.

             Timestamp timestamp;
             timestamp.set_seconds(time(NULL));
             timestamp.set_nanos(0);

         Example 2: Compute Timestamp from POSIX `gettimeofday()`.

             struct timeval tv;
             gettimeofday(&tv, NULL);

             Timestamp timestamp;
             timestamp.set_seconds(tv.tv_sec);
             timestamp.set_nanos(tv.tv_usec * 1000);

         Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`.

             FILETIME ft;
             GetSystemTimeAsFileTime(&ft);
             UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime;

             // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z
             // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z.
             Timestamp timestamp;
             timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL));
             timestamp.set_nanos((INT32) ((ticks % 10000000) * 100));

         Example 4: Compute Timestamp from Java `System.currentTimeMillis()`.

             long millis = System.currentTimeMillis();

             Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000)
                 .setNanos((int) ((millis % 1000) * 1000000)).build();

         Example 5: Compute Timestamp from Java `Instant.now()`.

             Instant now = Instant.now();

             Timestamp timestamp =
                 Timestamp.newBuilder().setSeconds(now.getEpochSecond())
                     .setNanos(now.getNano()).build();

         Example 6: Compute Timestamp from current time in Python.

             timestamp = Timestamp()
             timestamp.GetCurrentTime()

         # JSON Mapping

         In JSON format, the Timestamp type is encoded as a string in the
         [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the
         format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z"
         where {year} is always expressed using four digits while {month}, {day},
         {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional
         seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution),
         are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone
         is required. A proto3 JSON serializer should always use UTC (as indicated by
         "Z") when printing the Timestamp type and a proto3 JSON parser should be
         able to accept both UTC and other timezones (as indicated by an offset).

         For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past
         01:30 UTC on January 15, 2017.

         In JavaScript, one can convert a Date object to this format using the
         standard
         [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString)
         method. In Python, a standard `datetime.datetime` object can be converted
         to this format using
         [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with
         the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use
         the Joda Time's [`ISODateTimeFormat.dateTime()`](
         http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()
         ) to obtain a formatter capable of generating timestamps in this format.
    core.v1.ReportWidgetLayout:
      type: object
      properties:
        span:
          type: integer
          title: span
          maximum: 3
          minimum: 1
          format: int32
      title: ReportWidgetLayout
      additionalProperties: false
    core.v1.ReportAIUsageWidget:
      type: object
      properties:
        visualization:
          $ref: '#/components/schemas/core.v1.ReportVisualization'
          title: visualization
        metric:
          $ref: '#/components/schemas/core.v1.ReportAIMetric'
          not:
            enum:
              - REPORT_AI_METRIC_UNSPECIFIED
          title: metric
        dimension:
          $ref: '#/components/schemas/core.v1.ReportAIDimension'
          title: dimension
      title: ReportAIUsageWidget
      additionalProperties: false
      description: >-
        report_ai_usage_widget.dimension // a metric takes no dimension; bars,
        distributions and tables need one

        report_ai_usage_widget.visualization // an AI usage widget is a metric,
        bars, distribution or table
    core.v1.ReportLogsWidget:
      type: object
      properties:
        visualization:
          $ref: '#/components/schemas/core.v1.ReportVisualization'
          not:
            enum:
              - REPORT_VISUALIZATION_UNSPECIFIED
          title: visualization
        query:
          type: string
          title: query
          maxLength: 4000
        groupBy:
          type: array
          items:
            type: string
            maxLength: 256
            minLength: 1
          title: group_by
          maxItems: 2
        display:
          $ref: '#/components/schemas/core.v1.ReportLogsDisplay'
          title: display
      title: ReportLogsWidget
      additionalProperties: false
      description: >-
        report_logs_widget.heatmap_group_by // a heatmap needs exactly two
        group-by fields

        report_logs_widget.metric_group_by // a metric counts without group-by
        fields

        report_logs_widget.ranked_group_by // bars and distributions need
        exactly one group-by field

        report_logs_widget.table_group_by // a table needs one or two group-by
        fields

        report_logs_widget.timeseries_group_by // a timeseries splits by at most
        one group-by field
    core.v1.ReportNoteWidget:
      type: object
      properties:
        markdown:
          type: string
          title: markdown
          maxLength: 10000
          minLength: 1
      title: ReportNoteWidget
      additionalProperties: false
    core.v1.ReportVisualization:
      type: string
      title: ReportVisualization
      enum:
        - REPORT_VISUALIZATION_UNSPECIFIED
        - REPORT_VISUALIZATION_METRIC
        - REPORT_VISUALIZATION_TIMESERIES
        - REPORT_VISUALIZATION_BARS
        - REPORT_VISUALIZATION_DISTRIBUTION
        - REPORT_VISUALIZATION_TABLE
        - REPORT_VISUALIZATION_HEATMAP
    core.v1.ReportAIMetric:
      type: string
      title: ReportAIMetric
      enum:
        - REPORT_AI_METRIC_UNSPECIFIED
        - REPORT_AI_METRIC_ACTIVE_AI_USERS
        - REPORT_AI_METRIC_AI_ADOPTION
        - REPORT_AI_METRIC_SESSIONS
        - REPORT_AI_METRIC_REQUESTS
        - REPORT_AI_METRIC_POLICY_ACTIONS
        - REPORT_AI_METRIC_RISK_FINDINGS
    core.v1.ReportAIDimension:
      type: string
      title: ReportAIDimension
      enum:
        - REPORT_AI_DIMENSION_UNSPECIFIED
        - REPORT_AI_DIMENSION_APPLICATION
        - REPORT_AI_DIMENSION_LLM_PROVIDER
        - REPORT_AI_DIMENSION_AGENT_PROVIDER
        - REPORT_AI_DIMENSION_MODEL
        - REPORT_AI_DIMENSION_USER
        - REPORT_AI_DIMENSION_STOP_REASON
        - REPORT_AI_DIMENSION_TOOL
        - REPORT_AI_DIMENSION_POLICY_ACTION
        - REPORT_AI_DIMENSION_OWASP_CATEGORY
        - REPORT_AI_DIMENSION_POLICY_NAME
    core.v1.ReportLogsDisplay:
      type: object
      properties:
        limit:
          type: integer
          title: limit
          maximum: 200
          minimum: 0
          format: int32
        excludeOther:
          type: boolean
          title: exclude_other
        defaultInterval:
          $ref: '#/components/schemas/core.v1.ReportInterval'
          title: default_interval
        stacked:
          type: boolean
          title: stacked
      title: ReportLogsDisplay
      additionalProperties: false
    core.v1.ReportInterval:
      type: string
      title: ReportInterval
      enum:
        - REPORT_INTERVAL_UNSPECIFIED
        - REPORT_INTERVAL_HOUR
        - REPORT_INTERVAL_DAY
        - REPORT_INTERVAL_WEEK
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-KEY
      description: API key authentication. Get your API key from the Control Plane.

````

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