Matomo Custom Reports API

Exposes Custom Reports configuration and reporting endpoints. Use it to create, duplicate, manage, and query custom report definitions and their archived data.

Operations 13

GET /index.php?module=API&method=CustomReports.duplicateCustomReport #
GET /index.php?module=API&method=CustomReports.addCustomReport #
GET /index.php?module=API&method=CustomReports.updateCustomReport #
GET /index.php?module=API&method=CustomReports.getConfiguredReports #
GET /index.php?module=API&method=CustomReports.getConfiguredReport #
GET /index.php?module=API&method=CustomReports.deleteCustomReport #
GET /index.php?module=API&method=CustomReports.pauseCustomReport #
GET /index.php?module=API&method=CustomReports.resumeCustomReport #
GET /index.php?module=API&method=CustomReports.getAvailableCategories #
GET /index.php?module=API&method=CustomReports.getAvailableReportTypes #
GET /index.php?module=API&method=CustomReports.getAvailableDimensions #
GET /index.php?module=API&method=CustomReports.getAvailableMetrics #
GET /index.php?module=API&method=CustomReports.getCustomReport #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/matomo-customreports-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

matomo-customreports-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Matomo Reporting API for plugin Custom Reports API
  version: 1.0.0
  description: Exposes Custom Reports configuration and reporting endpoints. Use it to create, duplicate, manage, and query custom report definitions and their archived data.
servers:
- url: https://demo-proxy.innocraft.cloud/
  description: Current Matomo instance
security:
- MatomoToken: []
tags:
- name: CustomReports
  description: Exposes Custom Reports configuration and reporting endpoints. Use it to create, duplicate, manage, and query custom report definitions and their archived data.
paths:
  /index.php?module=API&method=CustomReports.duplicateCustomReport:
    get:
      tags:
      - CustomReports
      description: Duplicates a custom report to one or more websites.
      operationId: CustomReports.duplicateCustomReport
      parameters:
      - $ref: '#/components/parameters/formatOptional'
      - name: idSite
        in: query
        description: The numeric ID of the website that owns the source custom report.
        required: true
        schema:
          type: integer
          example: 1
      - name: idCustomReport
        in: query
        description: The ID of the custom report to duplicate.
        required: true
        schema:
          type: integer
          example: 1
      - name: idDestinationSites
        in: query
        description: Website IDs to copy the custom report to. Defaults to [$idSite] when omitted.
        required: false
        schema:
          type: array
          items:
            type: integer
          default: []
      responses:
        '200':
          description: 'Response indicating whether the duplication succeeded and, on success, the new report ID.


            Example responses require Super User access. Use Try it out to see a live response.'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/ServerError'
        default:
          $ref: '#/components/responses/DefaultError'
  /index.php?module=API&method=CustomReports.addCustomReport:
    get:
      tags:
      - CustomReports
      description: Creates a new custom report definition.
      operationId: CustomReports.addCustomReport
      parameters:
      - $ref: '#/components/parameters/formatOptional'
      - name: idSite
        in: query
        description: Website ID that owns the report, or "all"/0 when creating a shared report for multiple websites.
        required: true
        schema:
          oneOf:
          - type: integer
            example: 1
          - type: string
            example: '1'
      - name: name
        in: query
        description: The report name.
        required: true
        schema:
          type: string
          example: Pricing
      - name: reportType
        in: query
        description: Report type to create, for example "table", "evolution" or "kpicard".
        required: true
        schema:
          type: string
          example: table
      - name: metricIds
        in: query
        description: Metric IDs to include in the report.
        required: true
        schema:
          type: array
          items:
            type: string
          example:
          - nb_visits
          - nb_conversions
      - name: categoryId
        in: query
        description: Category ID to place the report in. Uses the default custom reports category when omitted.
        required: false
        schema:
          type: string
      - name: dimensionIds
        in: query
        description: Dimension IDs to include in the report.
        required: false
        schema:
          type: array
          items:
            type: string
          default: []
      - name: subcategoryId
        in: query
        description: Subcategory ID to place the report in. Creates a new reporting page when omitted.
        required: false
        schema:
          type: string
      - name: description
        in: query
        description: Optional report description shown in the report help tooltip.
        required: false
        schema:
          type: string
          default: ''
      - name: segmentFilter
        in: query
        description: Optional URL-encoded segment applied to the report data.
        required: false
        schema:
          type: string
          default: ''
      - name: multipleIdSites
        in: query
        description: Optional website IDs to assign the report to when creating a shared report.
        required: false
        schema:
          type: array
          items:
            type: string
          default: []
      responses:
        '200':
          description: 'The ID of the newly created custom report.


            Example responses require Super User access. Use Try it out to see a live response.'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/ServerError'
        default:
          $ref: '#/components/responses/DefaultError'
  /index.php?module=API&method=CustomReports.updateCustomReport:
    get:
      tags:
      - CustomReports
      description: Updates an existing custom report definition.
      operationId: CustomReports.updateCustomReport
      parameters:
      - $ref: '#/components/parameters/formatOptional'
      - name: idSite
        in: query
        description: Website ID that owns the report, or "all"/0 when updating a shared report.
        required: true
        schema:
          oneOf:
          - type: integer
            example: 1
          - type: string
            example: '1'
      - name: idCustomReport
        in: query
        description: The ID of the custom report to update.
        required: true
        schema:
          type: integer
          example: 1
      - name: name
        in: query
        description: The report name.
        required: true
        schema:
          type: string
          example: Pricing
      - name: reportType
        in: query
        description: Report type to store, for example "table", "evolution" or "kpicard".
        required: true
        schema:
          type: string
          example: table
      - name: metricIds
        in: query
        description: Metric IDs to include in the report.
        required: true
        schema:
          type: array
          items:
            type: string
          example:
          - nb_visits
          - nb_conversions
      - name: categoryId
        in: query
        description: Category ID to place the report in. Uses the default custom reports category when omitted.
        required: false
        schema:
          type: string
      - name: dimensionIds
        in: query
        description: Dimension IDs to include in the report.
        required: false
        schema:
          type: array
          items:
            type: string
          default: []
      - name: subcategoryId
        in: query
        description: Subcategory ID to place the report in. Creates a new reporting page when omitted.
        required: false
        schema:
          type: string
      - name: description
        in: query
        description: Optional report description shown in the report help tooltip.
        required: false
        schema:
          type: string
          default: ''
      - name: segmentFilter
        in: query
        description: Optional URL-encoded segment applied to the report data.
        required: false
        schema:
          type: string
          default: ''
      - name: subCategoryReportIds
        in: query
        description: Child report IDs mapped to this report.
        required: false
        schema:
          type: array
          items:
            type: integer
          default: []
      - name: multipleIdSites
        in: query
        description: Optional website IDs to assign the report to when updating a shared report.
        required: false
        schema:
          type: array
          items:
            type: string
          default: []
      responses:
        '200':
          $ref: '#/components/responses/GenericSuccess'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/ServerError'
        default:
          $ref: '#/components/responses/DefaultError'
  /index.php?module=API&method=CustomReports.getConfiguredReports:
    get:
      tags:
      - CustomReports
      description: Returns all configured custom reports for a website.
      operationId: CustomReports.getConfiguredReports
      parameters:
      - $ref: '#/components/parameters/formatOptional'
      - name: idSite
        in: query
        description: The website ID to query, or "all" for reports shared across all websites.
        required: true
        schema:
          oneOf:
          - type: integer
            example: 1
          - type: string
            example: '1'
      - name: skipCategoryMetadata
        in: query
        description: Whether to omit category metadata from each returned report.
        required: false
        schema:
          type: boolean
          default: false
      responses:
        '200':
          description: 'The configured custom reports for the requested website.


            Example responses require Super User access. Use Try it out to see a live response.'
          content:
            text/xml: []
            application/json: []
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/ServerError'
        default:
          $ref: '#/components/responses/DefaultError'
  /index.php?module=API&method=CustomReports.getConfiguredReport:
    get:
      tags:
      - CustomReports
      description: Returns a specific custom report configuration.
      operationId: CustomReports.getConfiguredReport
      parameters:
      - $ref: '#/components/parameters/formatOptional'
      - name: idSite
        in: query
        description: The website ID to query, or "all" for a report shared across all websites.
        required: true
        schema:
          oneOf:
          - type: integer
            example: 1
          - type: string
            example: '1'
      - name: idCustomReport
        in: query
        description: The ID of the custom report.
        required: true
        schema:
          type: integer
          example: 1
      responses:
        '200':
          description: 'The configured custom report details.


            Example responses require Super User access. Use Try it out to see a live response.'
          content:
            text/xml: []
            application/json: []
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/ServerError'
        default:
          $ref: '#/components/responses/DefaultError'
  /index.php?module=API&method=CustomReports.deleteCustomReport:
    get:
      tags:
      - CustomReports
      description: Deletes a custom report definition.
      operationId: CustomReports.deleteCustomReport
      parameters:
      - $ref: '#/components/parameters/formatOptional'
      - name: idSite
        in: query
        description: The website ID that owns the custom report, or "all" for a shared report.
        required: true
        schema:
          oneOf:
          - type: integer
            example: 1
          - type: string
            example: '1'
      - name: idCustomReport
        in: query
        description: The ID of the custom report to delete.
        required: true
        schema:
          type: integer
          example: 1
      responses:
        '200':
          $ref: '#/components/responses/GenericSuccess'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/ServerError'
        default:
          $ref: '#/components/responses/DefaultError'
  /index.php?module=API&method=CustomReports.pauseCustomReport:
    get:
      tags:
      - CustomReports
      description: Pauses a custom report.
      operationId: CustomReports.pauseCustomReport
      parameters:
      - $ref: '#/components/parameters/formatOptional'
      - name: idSite
        in: query
        description: The website ID that owns the custom report, or "all" for a shared report.
        required: true
        schema:
          oneOf:
          - type: integer
            example: 1
          - type: string
            example: '1'
      - name: idCustomReport
        in: query
        description: The ID of the custom report to pause.
        required: true
        schema:
          type: integer
          example: 1
      responses:
        '200':
          $ref: '#/components/responses/GenericSuccess'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/ServerError'
        default:
          $ref: '#/components/responses/DefaultError'
  /index.php?module=API&method=CustomReports.resumeCustomReport:
    get:
      tags:
      - CustomReports
      description: Resumes a paused custom report.
      operationId: CustomReports.resumeCustomReport
      parameters:
      - $ref: '#/components/parameters/formatOptional'
      - name: idSite
        in: query
        description: The website ID that owns the custom report, or "all" for a shared report.
        required: true
        schema:
          oneOf:
          - type: integer
            example: 1
          - type: string
            example: '1'
      - name: idCustomReport
        in: query
        description: The ID of the custom report to resume.
        required: true
        schema:
          type: integer
          example: 1
      responses:
        '200':
          $ref: '#/components/responses/GenericSuccess'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/ServerError'
        default:
          $ref: '#/components/responses/DefaultError'
  /index.php?module=API&method=CustomReports.getAvailableCategories:
    get:
      tags:
      - CustomReports
      description: Returns report categories and subcategories that can contain custom reports.
      operationId: CustomReports.getAvailableCategories
      parameters:
      - $ref: '#/components/parameters/formatOptional'
      - name: idSite
        in: query
        description: The website ID used to resolve available report pages.
        required: true
        schema:
          oneOf:
          - type: integer
            example: 1
          - type: string
            example: '1'
      responses:
        '200':
          description: 'Available categories and subcategories for custom report placement.


            Example responses require Super User access. Use Try it out to see a live response.'
          content:
            text/xml: []
            application/json: []
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/ServerError'
        default:
          $ref: '#/components/responses/DefaultError'
  /index.php?module=API&method=CustomReports.getAvailableReportTypes:
    get:
      tags:
      - CustomReports
      description: Returns report types that can be used for custom reports.
      operationId: CustomReports.getAvailableReportTypes
      parameters:
      - $ref: '#/components/parameters/formatOptional'
      responses:
        '200':
          description: 'Available custom report types keyed by identifier and translated name.


            Example responses require Super User access. Use Try it out to see a live response.'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/ServerError'
        default:
          $ref: '#/components/responses/DefaultError'
  /index.php?module=API&method=CustomReports.getAvailableDimensions:
    get:
      tags:
      - CustomReports
      description: Returns dimensions that can be used in custom reports.
      operationId: CustomReports.getAvailableDimensions
      parameters:
      - $ref: '#/components/parameters/formatOptional'
      - name: idSite
        in: query
        description: The website ID used to resolve available dimensions.
        required: true
        schema:
          oneOf:
          - type: integer
            example: 1
          - type: string
            example: '1'
      responses:
        '200':
          description: 'Available dimensions grouped by category.


            Example responses require Super User access. Use Try it out to see a live response.'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/ServerError'
        default:
          $ref: '#/components/responses/DefaultError'
  /index.php?module=API&method=CustomReports.getAvailableMetrics:
    get:
      tags:
      - CustomReports
      description: Returns metrics that can be used in custom reports.
      operationId: CustomReports.getAvailableMetrics
      parameters:
      - $ref: '#/components/parameters/formatOptional'
      - name: idSite
        in: query
        description: The website ID used to resolve available metrics.
        required: true
        schema:
          oneOf:
          - type: integer
            example: 1
          - type: string
            example: '1'
      responses:
        '200':
          description: 'Available metrics grouped by category.


            Example responses require Super User access. Use Try it out to see a live response.'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/ServerError'
        default:
          $ref: '#/components/responses/DefaultError'
  /index.php?module=API&method=CustomReports.getCustomReport:
    get:
      tags:
      - CustomReports
      description: Returns archived data for a configured custom report.
      operationId: CustomReports.getCustomReport
      parameters:
      - $ref: '#/components/parameters/formatOptional'
      - name: idSite
        in: query
        description: The website ID to query.
        required: true
        schema:
          oneOf:
          - type: integer
            example: 1
          - type: string
            example: '1'
      - name: period
        in: query
        description: The period to process, processes data for the period containing the specified date.
        required: true
        schema:
          type: string
          enum:
          - day
          - week
          - month
          - year
          - range
          example: day
      - name: date
        in: query
        description: The date or date range to process. 'YYYY-MM-DD', magic keywords (today, yesterday, lastWeek, lastMonth, lastYear), or date range (ie, 'YYYY-MM-DD,YYYY-MM-DD', lastX, previousX).
        required: true
        schema:
          type: string
          example: yesterday
      - name: idCustomReport
        in: query
        description: The ID of the custom report to look up data for.
        required: true
        schema:
          type: integer
          example: 1
      - name: segment
        in: query
        description: 'Custom segment to filter the report. Example: "referrerName==example.com" Supports AND (;) and OR (,) operators.'
        required: false
        schema:
          type: string
      - name: expanded
        in: query
        description: Whether to expand recursive subtables in the response.
        required: false
        schema:
          type: boolean
          default: false
      - name: flat
        in: query
        description: Whether to flatten the report rows into a single level.
        required: false
        schema:
          type: boolean
          default: false
      - name: idSubtable
        in: query
        description: The subtable ID to fetch instead of the root table.
        required: false
        schema:
          oneOf:
          - type: integer
          - type: string
      - name: columns
        in: query
        description: Comma-separated list of columns to include in the response.
        required: false
        schema:
          type: string
      responses:
        '200':
          description: 'The archived data for the requested custom report.


            Example responses require Super User access. Use Try it out to see a live response.'
          content:
            text/xml: []
            application/json: []
            application/vnd.ms-excel: []
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/ServerError'
        default:
          $ref: '#/components/responses/DefaultError'
components:
  schemas:
    GenericSuccessXml:
      description: Generic Matomo success payload in XML.
      required:
      - success
      properties:
        success:
          properties:
            message:
              type: string
              xml:
                attribute: true
              example: ok
          type: object
          xml:
            name: success
      type: object
      xml:
        name: result
      example:
        success:
          message: ok
      additionalProperties: true
    GenericSuccess:
      description: Generic Matomo success payload.
      required:
      - result
      - message
      properties:
        result:
          type: string
          example: success
        message:
          type: string
          example: ok
        code:
          type: integer
          example: '200'
      type: object
      example:
        result: success
        message: ok
      additionalProperties: true
    ErrorXml:
      description: Generic Matomo error payload in XML.
      properties:
        error:
          properties:
            message:
              type: string
              xml:
                attribute: true
              example: There was an error
          type: object
          xml:
            name: error
      type: object
      xml:
        name: result
    Error:
      description: Generic Matomo error payload.
      required:
      - result
      - message
      properties:
        result:
          type: string
          example: error
        message:
          type: string
          example: There was an error
        code:
          type: integer
      type: object
      additionalProperties: true
  responses:
    NotFound:
      description: Resource not found.
      content:
        text/plain:
          schema:
            type: string
          example: 'Error: The method is not available.'
        text/html:
          schema:
            type: string
          example: The method is not available.
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
        application/xml:
          schema:
            $ref: '#/components/schemas/ErrorXml'
    ServerError:
      description: Unexpected server error.
      content:
        text/plain:
          schema:
            type: string
          example: 'Error: There was an error.'
        text/html:
          schema:
            type: string
          example: There was an error.
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
        application/xml:
          schema:
            $ref: '#/components/schemas/ErrorXml'
    Unauthorized:
      description: Authentication failed or missing token.
      content:
        text/plain:
          schema:
            type: string
          example: 'Error: You must be logged in to access this functionality.'
        text/html:
          schema:
            type: string
          example: You must be logged in to access this functionality.
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
        application/xml:
          schema:
            $ref: '#/components/schemas/ErrorXml'
    Forbidden:
      description: Authenticated but not allowed to access the resource.
      content:
        text/plain:
          schema:
            type: string
          example: 'Error: Not authorised.'
        text/html:
          schema:
            type: string
          example: Not authorised.
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
        application/xml:
          schema:
            $ref: '#/components/schemas/ErrorXml'
    DefaultError:
      description: Default error response (any non-2xx).
      content:
        text/plain:
          schema:
            type: string
          example: 'Error: There was an error.'
        text/html:
          schema:
            type: string
          example: There was an error.
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
        application/xml:
          schema:
            $ref: '#/components/schemas/ErrorXml'
    GenericSuccess:
      description: Generic 200 response
      content:
        text/plain:
          schema:
            type: string
          example: Success:ok
        text/html:
          schema:
            type: string
          example: '<!-- Success: ok -->'
        application/json:
          schema:
            $ref: '#/components/schemas/GenericSuccess'
        application/xml:
          schema:
            $ref: '#/components/schemas/GenericSuccessXml'
    BadRequest:
      description: Bad request (validation or missing parameters).
      content:
        text/plain:
          schema:
            type: string
          example: 'Error: There was an error.'
        text/html:
          schema:
            type: string
          example: There was an error.
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
        application/xml:
          schema:
            $ref: '#/components/schemas/ErrorXml'
  parameters:
    formatOptional:
      name: format
      in: query
      description: Response format. Defaults to `xml`. Use `original` to get the original PHP data structure.
      required: false
      schema:
        type: string
        default: xml
        enum:
        - xml
        - json
        - csv
        - tsv
        - html
        - rss
        - original
  securitySchemes:
    MatomoToken:
      type: http
      description: Paste your token generated from Personal > Security. Swagger will send it as a Bearer token.
      scheme: bearer
externalDocs:
  description: Matomo Reporting API developer page
  url: https://developer.matomo.org/api-reference/reporting-api/