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

# Create dashboard

> Creates a dashboard owned by the caller, either from the cards in the request body or as a copy of a template (`templateId`). Every card gets its own widget row, so editing a card never changes the widget catalogue or another dashboard. See the [Dashboard overview](/api-reference/analytics/dashboard-overview) for the card and layout rules.



## OpenAPI

````yaml /openapi/public/openapi-analytics.json post /dynamic-dashboard
openapi: 3.0.0
info:
  title: MileApp API - Analytics
  version: 3.0.0
  description: MileApp API Documentation - RESTful API for field operations management.
servers:
  - url: https://apiweb.mile.app/api/v3
security:
  - bearerAuth: []
tags:
  - name: Dashboard
    description: >-
      Dashboard lets a user compose their own dashboard from any number of
      cards, start from a template, duplicate a dashboard, share it with roles,
      and save it back as an organization template. Each card owns its own
      widget row (a chart type plus a query spec), cloned from the widget
      catalogue (built-in widgets plus the organization's custom widgets), so
      renaming or editing a card never touches the catalogue or another
      dashboard. Dashboards are owned by their creator: roles they are shared
      with can view, duplicate and save as template, but only the owner can edit
      or delete. Every write reuses the dashboard permission family (view, add,
      edit and delete dashboard).


      The numbers behind each card come from one generic aggregation endpoint
      instead of one endpoint per chart: the client sends a batch of up to 12
      declarative query specs, the server injects the caller's organization, hub
      and soft-delete scope from the session, runs each spec read-only, and
      returns a flat columns and rows table per item. The catalog endpoints
      describe the data sources, fields and limits a client may use.
paths:
  /dynamic-dashboard:
    post:
      tags:
        - Dashboard
      summary: Create dashboard
      description: >-
        Creates a dashboard owned by the caller, either from the cards in the
        request body or as a copy of a template (`templateId`). Every card gets
        its own widget row, so editing a card never changes the widget catalogue
        or another dashboard. See the [Dashboard
        overview](/api-reference/analytics/dashboard-overview) for the card and
        layout rules.
      operationId: createDynamicDashboard
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
                - name
              properties:
                name:
                  type: string
                  maxLength: 200
                description:
                  type: string
                templateId:
                  type: string
                  maxLength: 200
                  description: >-
                    Template name (for example `dailyOperations`), not its
                    `_id`. Names are stable across environments; ObjectIds are
                    not.
                sharedRoleIds:
                  type: array
                  maxItems: 50
                  items:
                    type: string
                  description: >-
                    Role ids, each distinct. Absent = shared with the creator's
                    own role; explicit `[]` = private.
                hubScope:
                  type: object
                  properties:
                    mode:
                      type: string
                      enum:
                        - all
                        - selected
                      description: Required whenever `hubScope` is sent
                    hubIds:
                      type: array
                      maxItems: 200
                      items:
                        type: string
                timeRange:
                  type: object
                  description: >-
                    Default time window for the dashboard, or `null`. Not
                    interpreted by the CRUD layer; the analytics endpoint
                    accepts `today`, `yesterday`, `last_7d`, `last_30d`.
                  properties:
                    preset:
                      type: string
                      maxLength: 50
                grid:
                  type: object
                  properties:
                    columns:
                      type: integer
                      minimum: 1
                      maximum: 48
                      description: Column count, default 12. Stored per document.
                    engine:
                      type: string
                      enum:
                        - flow
                        - absolute
                      description: Optional layout engine hint
                widgets:
                  type: array
                  items:
                    type: object
                    properties:
                      widgetId:
                        type: string
                        pattern: ^[0-9a-fA-F]{24}$
                      widgetName:
                        type: string
                        maxLength: 200
                      widget:
                        type: object
                        description: >-
                          A widget definition (a `dynamicWidgets` row without
                          identity and audit fields)
                        properties:
                          schemaVersion:
                            type: integer
                            example: 1
                          name:
                            type: string
                            maxLength: 200
                            description: Literal display name, never translated
                          description:
                            type: string
                          category:
                            type: string
                            enum:
                              - overview
                              - taskStatus
                              - productivity
                              - timeDuration
                              - team
                              - hub
                              - trend
                              - utility
                          viz:
                            type: string
                            description: >-
                              Visualization: kpi, bar, line, donut, table,
                              heatmap, text, banner
                          spec:
                            type: object
                            description: >-
                              Neutral analytics query spec executed by POST
                              /analytics/query. See Run analytics query for the
                              full grammar.
                            properties:
                              specVersion:
                                type: integer
                              dataSourceId:
                                type: string
                              timeField:
                                type: string
                              measures:
                                type: array
                                items:
                                  type: object
                                  additionalProperties: true
                              dimensions:
                                type: array
                                items:
                                  type: object
                                  additionalProperties: true
                              filters:
                                type: array
                                items:
                                  type: object
                                  additionalProperties: true
                          composite:
                            type: object
                            description: >-
                              Multi-query widget `{kind, queries: {key: spec}}`;
                              `null` for ordinary widgets
                            additionalProperties: true
                          content:
                            type: object
                            description: >-
                              `{body}` for text and banner widgets; `null`
                              otherwise
                            properties:
                              body:
                                type: string
                                maxLength: 2000
                          defaultLayout:
                            type: object
                            description: Card placement on the grid
                            properties:
                              w:
                                type: integer
                                minimum: 2
                                description: Width in grid columns, 2 to `grid.columns`
                              h:
                                type: integer
                                minimum: 3
                                maximum: 18
                                description: >-
                                  Height in rows, 3-18; `null` = as tall as its
                                  content
                              x:
                                type: integer
                                minimum: 0
                                maximum: 48
                                description: >-
                                  Optional column offset (free placement
                                  accepted, not required)
                              'y':
                                type: integer
                                minimum: 0
                                description: Optional row offset
                      layout:
                        type: object
                        description: Card placement on the grid
                        properties:
                          w:
                            type: integer
                            minimum: 2
                            description: Width in grid columns, 2 to `grid.columns`
                          h:
                            type: integer
                            minimum: 3
                            maximum: 18
                            description: >-
                              Height in rows, 3-18; `null` = as tall as its
                              content
                          x:
                            type: integer
                            minimum: 0
                            maximum: 48
                            description: >-
                              Optional column offset (free placement accepted,
                              not required)
                          'y':
                            type: integer
                            minimum: 0
                            description: Optional row offset
                      cardId:
                        type: string
                        maxLength: 64
                        description: Ignored on create; the server assigns fresh ids
              example:
                name: Jakarta Hub - Daily
                description: Morning stand-up view
                sharedRoleIds:
                  - 6650c2a1f3b9e4001c7d2b20
                hubScope:
                  mode: selected
                  hubIds:
                    - 6650c2a1f3b9e4001c7d2c30
                timeRange:
                  preset: last_7d
                grid:
                  columns: 12
                widgets:
                  - widgetName: Total Tasks
                    layout:
                      w: 3
                      h: null
                  - widgetId: 66e0b3f1c9a8d7e6f5a4b202
                    layout:
                      w: 6
                      h: 6
                      x: 3
                      'y': 0
                  - widget:
                      name: Shift notes
                      viz: text
                      category: utility
                      spec: null
                      content:
                        body: Check the Bekasi backlog first.
                      defaultLayout:
                        w: 3
                        h: null
                    layout:
                      w: 3
                      h: 3
        description: Dashboard to create
        required: true
      responses:
        '201':
          description: Created - the new dashboard, with widget definitions attached
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: boolean
                    example: true
                  code:
                    type: integer
                  message:
                    type: string
                  data:
                    type: object
                    properties:
                      _id:
                        type: string
                      organizationId:
                        type: string
                        description: Stamped from the caller's session; immutable
                      schemaVersion:
                        type: integer
                        example: 1
                      name:
                        type: string
                      description:
                        type: string
                      sharedRoleIds:
                        type: array
                        items:
                          type: string
                        description: >-
                          The whole sharing state: empty = only the owner,
                          non-empty = those roles as well (read-only for them)
                      hubScope:
                        type: object
                        properties:
                          mode:
                            type: string
                            enum:
                              - all
                              - selected
                            description: Required whenever `hubScope` is sent
                          hubIds:
                            type: array
                            maxItems: 200
                            items:
                              type: string
                      timeRange:
                        type: object
                        description: >-
                          Default time window for the dashboard, or `null`. Not
                          interpreted by the CRUD layer; the analytics endpoint
                          accepts `today`, `yesterday`, `last_7d`, `last_30d`.
                        properties:
                          preset:
                            type: string
                            maxLength: 50
                      grid:
                        type: object
                        properties:
                          columns:
                            type: integer
                            minimum: 1
                            maximum: 48
                            description: Column count, default 12. Stored per document.
                          engine:
                            type: string
                            enum:
                              - flow
                              - absolute
                            description: Optional layout engine hint
                      widgets:
                        type: array
                        items:
                          type: object
                          description: >-
                            A card on a dashboard. Stored cards carry only the
                            reference; `widget` is attached on read.
                          properties:
                            cardId:
                              type: string
                              description: >-
                                Stable card id `crd_` followed by a ULID,
                                assigned by the server. Also the batch key of
                                the analytics request.
                            widgetId:
                              type: string
                              description: The `dynamicWidgets` row this card owns
                            widgetName:
                              type: string
                              description: Label that follows the row's name
                            layout:
                              type: object
                              description: Card placement on the grid
                              properties:
                                w:
                                  type: integer
                                  minimum: 2
                                  description: Width in grid columns, 2 to `grid.columns`
                                h:
                                  type: integer
                                  minimum: 3
                                  maximum: 18
                                  description: >-
                                    Height in rows, 3-18; `null` = as tall as
                                    its content
                                x:
                                  type: integer
                                  minimum: 0
                                  maximum: 48
                                  description: >-
                                    Optional column offset (free placement
                                    accepted, not required)
                                'y':
                                  type: integer
                                  minimum: 0
                                  description: Optional row offset
                            widget:
                              type: object
                              description: >-
                                A widget definition (a `dynamicWidgets` row
                                without identity and audit fields)
                              properties:
                                schemaVersion:
                                  type: integer
                                  example: 1
                                name:
                                  type: string
                                  maxLength: 200
                                  description: Literal display name, never translated
                                description:
                                  type: string
                                category:
                                  type: string
                                  enum:
                                    - overview
                                    - taskStatus
                                    - productivity
                                    - timeDuration
                                    - team
                                    - hub
                                    - trend
                                    - utility
                                viz:
                                  type: string
                                  description: >-
                                    Visualization: kpi, bar, line, donut, table,
                                    heatmap, text, banner
                                spec:
                                  type: object
                                  description: >-
                                    Neutral analytics query spec executed by
                                    POST /analytics/query. See Run analytics
                                    query for the full grammar.
                                  properties:
                                    specVersion:
                                      type: integer
                                    dataSourceId:
                                      type: string
                                    timeField:
                                      type: string
                                    measures:
                                      type: array
                                      items:
                                        type: object
                                        additionalProperties: true
                                    dimensions:
                                      type: array
                                      items:
                                        type: object
                                        additionalProperties: true
                                    filters:
                                      type: array
                                      items:
                                        type: object
                                        additionalProperties: true
                                composite:
                                  type: object
                                  description: >-
                                    Multi-query widget `{kind, queries: {key:
                                    spec}}`; `null` for ordinary widgets
                                  additionalProperties: true
                                content:
                                  type: object
                                  description: >-
                                    `{body}` for text and banner widgets; `null`
                                    otherwise
                                  properties:
                                    body:
                                      type: string
                                      maxLength: 2000
                                defaultLayout:
                                  type: object
                                  description: Card placement on the grid
                                  properties:
                                    w:
                                      type: integer
                                      minimum: 2
                                      description: >-
                                        Width in grid columns, 2 to
                                        `grid.columns`
                                    h:
                                      type: integer
                                      minimum: 3
                                      maximum: 18
                                      description: >-
                                        Height in rows, 3-18; `null` = as tall
                                        as its content
                                    x:
                                      type: integer
                                      minimum: 0
                                      maximum: 48
                                      description: >-
                                        Optional column offset (free placement
                                        accepted, not required)
                                    'y':
                                      type: integer
                                      minimum: 0
                                      description: Optional row offset
                      origin:
                        type: object
                        description: Provenance only; nothing dereferences `sourceId`
                        properties:
                          kind:
                            type: string
                            enum:
                              - blank
                              - template
                              - duplicate
                              - dashboard
                          sourceId:
                            type: string
                          sourceSchemaVersion:
                            type: integer
                          copiedAt:
                            type: string
                            format: date-time
                      createdBy:
                        type: string
                        description: Owner's email. Only the owner may PATCH or DELETE.
                      updatedBy:
                        type: string
                      createdTime:
                        type: string
                        format: date-time
                      updatedTime:
                        type: string
                        format: date-time
                        description: >-
                          Echo this back on PATCH as the lost-update
                          precondition
              examples:
                response:
                  value:
                    status: true
                    code: 201
                    message: Dashboard has been added successfully.
                    data:
                      _id: 66f9a1c2e4b0a7d3c1f20a11
                      organizationId: 6650c2a1f3b9e4001c7d2a10
                      schemaVersion: 1
                      name: Jakarta Hub - Daily
                      description: Morning stand-up view
                      sharedRoleIds:
                        - 6650c2a1f3b9e4001c7d2b20
                      hubScope:
                        mode: selected
                        hubIds:
                          - 6650c2a1f3b9e4001c7d2c30
                      timeRange:
                        preset: last_7d
                      grid:
                        columns: 12
                      widgets:
                        - cardId: crd_01J8ZQ4R5W6X7Y8Z9A0B1C2D3E
                          widgetId: 66f9a1c2e4b0a7d3c1f20b01
                          widgetName: Total Tasks
                          layout:
                            w: 3
                            h: null
                          widget:
                            schemaVersion: 1
                            name: Total Tasks
                            description: >-
                              Tasks whose start time falls in the selected
                              range, across every status.
                            category: overview
                            viz: kpi
                            spec:
                              specVersion: 1
                              dataSourceId: task
                              timeField: startTime
                              measures:
                                - id: m1
                                  fn: count
                              dimensions: []
                              filters: []
                            composite: null
                            content: null
                            defaultLayout:
                              w: 3
                              h: null
                        - cardId: crd_01J8ZQ4R5W6X7Y8Z9A0B1C2D3F
                          widgetId: 66f9a1c2e4b0a7d3c1f20b02
                          widgetName: Tasks by Status
                          layout:
                            w: 6
                            h: 6
                            x: 3
                            'y': 0
                          widget:
                            schemaVersion: 1
                            name: Tasks by Status
                            description: Task count per status in the selected range.
                            category: taskStatus
                            viz: donut
                            spec:
                              specVersion: 1
                              dataSourceId: task
                              timeField: startTime
                              measures:
                                - id: m1
                                  fn: count
                              dimensions:
                                - id: d1
                                  kind: terms
                                  field: status
                                  limit: 3
                              filters: []
                            composite: null
                            content: null
                            defaultLayout:
                              w: 6
                              h: 6
                        - cardId: crd_01J8ZQ4R5W6X7Y8Z9A0B1C2D3G
                          widgetId: 66f9a1c2e4b0a7d3c1f20b03
                          widgetName: Shift notes
                          layout:
                            w: 3
                            h: 3
                          widget:
                            schemaVersion: 1
                            name: Shift notes
                            description: null
                            category: utility
                            viz: text
                            spec: null
                            composite: null
                            content:
                              body: Check the Bekasi backlog first.
                            defaultLayout:
                              w: 3
                              h: null
                      origin:
                        kind: blank
                        sourceId: null
                        sourceSchemaVersion: null
                        copiedAt: '2026-09-30T08:10:44+07:00'
                      createdBy: ops.lead@example.com
                      updatedBy: ops.lead@example.com
                      createdTime: '2026-09-30T01:10:44.512000Z'
                      updatedTime: '2026-09-30T01:10:44.512000Z'
        '400':
          description: >-
            Bad Request - validation failed. `dydsh-001` missing/blank required
            field, `dydsh-002` repeated role id, `dydsh-003` bad `widgetId`
            format or `overrides` present, `dydsh-009` length/range, `dydsh-011`
            not an array, `dydsh-013` card with no reference or an ambiguous
            `widgetName`, `dydsh-014` an inline widget `viz` or `spec` is not
            valid, `dydsh-037` unknown widget id or name.
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: boolean
                    example: false
                  message:
                    type: string
                    description: Human-readable reason
                  failedCode:
                    type: string
                    description: Structured error code, see Status Codes
              examples:
                response:
                  value:
                    status: false
                    message: No widget definition is named Daily Volume.
                    failedCode: dydsh-037
        '401':
          description: Unauthorized - missing, invalid or expired access token
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: boolean
                    example: false
                  message:
                    type: string
                    description: Human-readable reason
                  failedCode:
                    type: string
                    description: Structured error code, see Status Codes
              examples:
                response:
                  value:
                    status: false
                    message: Unauthenticated.
                    failedCode: auth-034
        '403':
          description: Forbidden - the caller's role lacks `add/dashboard`
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: boolean
                    example: false
                  message:
                    type: string
                    description: Human-readable reason
                  failedCode:
                    type: string
                    description: Structured error code, see Status Codes
              examples:
                response:
                  value:
                    status: false
                    message: >-
                      Access denied. You do not have permission for add
                      dashboard. Please contact your admin to request access.
                    failedCode: sys-035
        '404':
          description: >-
            Not Found - no template with that `templateId` name is visible to
            the caller
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: boolean
                    example: false
                  message:
                    type: string
                    description: Human-readable reason
                  failedCode:
                    type: string
                    description: Structured error code, see Status Codes
                  code:
                    type: integer
                    description: >-
                      HTTP status repeated in the body (repository failures
                      only)
                  data:
                    type: array
                    items:
                      type: object
                      additionalProperties: true
                    description: Empty on most failures
              examples:
                response:
                  value:
                    status: false
                    code: 404
                    message: Dashboard template not found.
                    failedCode: dydsh-038
        '422':
          description: >-
            Unprocessable - the document was written by a newer schema version
            than this API node understands (transient during a rolling deploy).
            Nothing was written.
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: boolean
                    example: false
                  message:
                    type: string
                    description: Human-readable reason
                  failedCode:
                    type: string
                    description: Structured error code, see Status Codes
                  code:
                    type: integer
                    description: >-
                      HTTP status repeated in the body (repository failures
                      only)
                  data:
                    type: array
                    items:
                      type: object
                      additionalProperties: true
                    description: Empty on most failures
              examples:
                response:
                  value:
                    status: false
                    code: 422
                    message: >-
                      This dashboard was saved by a newer version of MileApp and
                      cannot be opened here. Please refresh the page and try
                      again.
                    data: []
                    failedCode: dydsh-040
        '500':
          description: Server Error - unexpected exception, logged server-side
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: boolean
                    example: false
                  message:
                    type: string
                    description: Human-readable reason
                  failedCode:
                    type: string
                    description: Structured error code, see Status Codes
                  code:
                    type: integer
                    description: >-
                      HTTP status repeated in the body (repository failures
                      only)
                  data:
                    type: array
                    items:
                      type: object
                      additionalProperties: true
                    description: Empty on most failures
              examples:
                response:
                  value:
                    status: false
                    code: 500
                    message: something_wrong
                    failedCode: dydsh-045
      security:
        - bearerAuth: []
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: Use a valid Bearer token to authenticate.

````

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