# REST API operations Source: https://docs.cortex.io/api Programmatic access to your entities, Scorecards, Workflows, and more ## Cortex API The Cortex REST API provides programmatic access to your entities, Scorecards, Workflows, and more. ### Base URL Send API requests to the base URL for the region or deployment where your Cortex workspace is hosted: | Deployment | Base URL | | - | - | | US | `https://api.getcortexapp.com` | | EU | `https://api.eu.cortex.io` | | Self-managed | Your Cortex backend URL (for example, `https://cortex-api.yourdomain.example`) | If you're not sure which region your workspace is in, check the URL you use to log in. If it starts with `app.eu.cortex.io`, use the EU base URL. If it starts with `app.getcortexapp.com`, use the US base URL. For self-managed Cortex, use the hostname you set as `app.hostnames.backend` in your Helm chart values. ### Authentication All requests to the Cortex API need to provide an `Authorization: Bearer ` header, where `` is an API key created in the Settings page of your workspace. | Security Scheme Type: | http | | - | - | | HTTP Authorization Scheme | bearer | | Bearer format: | JWT | ### Operations See the sub-pages in this section for all available operations. Throughout these documentation pages, click **Try it** under an operation to send a request directly from the documentation page. Before you send it, click the base URL next to the endpoint path and select the one that matches your workspace. For self-managed Cortex, select `{baseUrl}`, then enter your backend URL in the **baseUrl** field under **Server**. ![The selector icon in the base URL.](https://mintcdn.com/cortex-290c0c42/KuOyXNHfLFf7MXsJ/images/api-selector.png?fit=max\&auto=format\&n=KuOyXNHfLFf7MXsJ\&q=85\&s=21e5efd6e3dd652c456784fd62327c9b) ![A list of the available base URLs for the API.](https://mintcdn.com/cortex-290c0c42/KuOyXNHfLFf7MXsJ/images/api-selector-urls.png?fit=max\&auto=format\&n=KuOyXNHfLFf7MXsJ\&q=85\&s=761f59ea067e2052b6b169723da61e40) ### Rate limiting The Cortex API limits requests to 1000 per minute per client. The body size of any given request has a maximum of 2MB. If you attempt too many requests in a short period, a `429` error will be returned with a `Retry-After` header. If you are hitting rate limits frequently, please contact your Cortex Customer Success Manager to discuss your use case. > [!NOTE] > > API rate limits are subject to change. Customers will be notified of any changes made to the rate limits. # Add a single configuration Source: https://docs.cortex.io/api/rest/anthropic-api/add-a-single-configuration /openapi/cortex_swagger.json post /api/v1/anthropic/configuration # Add multiple configurations Source: https://docs.cortex.io/api/rest/anthropic-api/add-multiple-configurations /openapi/cortex_swagger.json post /api/v1/anthropic/configurations # Delete a configuration Source: https://docs.cortex.io/api/rest/anthropic-api/delete-a-configuration /openapi/cortex_swagger.json delete /api/v1/anthropic/configuration/{alias} # Delete all configurations Source: https://docs.cortex.io/api/rest/anthropic-api/delete-all-configurations /openapi/cortex_swagger.json delete /api/v1/anthropic/configurations # Retrieve a configuration Source: https://docs.cortex.io/api/rest/anthropic-api/retrieve-a-configuration /openapi/cortex_swagger.json get /api/v1/anthropic/configuration/{alias} # Retrieve configurations Source: https://docs.cortex.io/api/rest/anthropic-api/retrieve-configurations /openapi/cortex_swagger.json get /api/v1/anthropic/configurations # Retrieve default configuration Source: https://docs.cortex.io/api/rest/anthropic-api/retrieve-default-configuration /openapi/cortex_swagger.json get /api/v1/anthropic/default-configuration # Update a configuration Source: https://docs.cortex.io/api/rest/anthropic-api/update-a-configuration /openapi/cortex_swagger.json put /api/v1/anthropic/configuration/{alias} WARNING: Updating aliases for configurations or changing the default configuration could cause entity YAMLs that use this integration to break. # Validate a configuration Source: https://docs.cortex.io/api/rest/anthropic-api/validate-a-configuration /openapi/cortex_swagger.json post /api/v1/anthropic/configuration/validate/{alias} # Validate all configurations Source: https://docs.cortex.io/api/rest/anthropic-api/validate-all-configurations /openapi/cortex_swagger.json post /api/v1/anthropic/configuration/validate # API Keys Source: https://docs.cortex.io/api/rest/api-keys Use these operations to interact with [API keys](/configure/settings/api-keys) in Cortex. ### Required permissions Your API token must have the `Edit API keys` permission. ### Roles When creating an API key, you must specify roles. Each role requires a `type` field set to `DEFAULT` or `CUSTOM`. You can assign multiple roles (both default and custom) to a single API key. **Default roles** use the `role` field to specify the permission level. Allowed values: `READ_ONLY`, `USER`, `ADMIN`. ```json theme={null} { "type": "DEFAULT", "role": "READ_ONLY" } ``` **Custom roles** use the `tag` field (not `role`) to reference a [custom role](/configure/settings/managing-users/permissioning/custom-roles) by its unique tag: ```json theme={null} { "type": "CUSTOM", "tag": "custom-role-tag" } ``` **Example payload with multiple roles:** ```json theme={null} { "name": "Entities scanner", "roles": [ { "type": "DEFAULT", "role": "ADMIN" }, { "type": "CUSTOM", "tag": "custom-role-tag" } ] } ``` > [!NOTE] > > Note: Users with custom roles can only create API keys assigned to roles with equal or fewer permissions than their own. ## Operations > **[List API keys](/api/rest/api-keys/list-api-keys)** > > `GET /api/v1/auth/key` > **[Get API key](/api/rest/api-keys/get-api-key)** > > `GET /api/v1/auth/key/{cid}` > **[Create API key](/api/rest/api-keys/create-api-key)** > > `POST /api/v1/auth/key` > **[Update API key](/api/rest/api-keys/update-api-key)** > > `PUT /api/v1/auth/key/{cid}` > **[Delete API key](/api/rest/api-keys/delete-api-key)** > > `DELETE /api/v1/auth/key/{cid}` # Create API key Source: https://docs.cortex.io/api/rest/api-keys/create-api-key /openapi/cortex_swagger.json post /api/v1/auth/key Create new API key. The API key used to make the request must have the `Edit API keys` permission # Delete API key Source: https://docs.cortex.io/api/rest/api-keys/delete-api-key /openapi/cortex_swagger.json delete /api/v1/auth/key/{cid} Delete API key The API key used to make the request must have the `Edit API keys` permission # Get API key Source: https://docs.cortex.io/api/rest/api-keys/get-api-key /openapi/cortex_swagger.json get /api/v1/auth/key/{cid} Get API key # List API keys Source: https://docs.cortex.io/api/rest/api-keys/list-api-keys /openapi/cortex_swagger.json get /api/v1/auth/key List API keys The API key used to make the request must have the `Edit API keys` permission # Update API key Source: https://docs.cortex.io/api/rest/api-keys/update-api-key /openapi/cortex_swagger.json put /api/v1/auth/key/{cid} Update API key The API key used to make the request must have the `Edit API keys` permission # Add a single configuration Source: https://docs.cortex.io/api/rest/apiiro-api/add-a-single-configuration /openapi/cortex_swagger.json post /api/v1/apiiro/configuration # Add multiple configurations Source: https://docs.cortex.io/api/rest/apiiro-api/add-multiple-configurations /openapi/cortex_swagger.json post /api/v1/apiiro/configurations # Delete a configuration Source: https://docs.cortex.io/api/rest/apiiro-api/delete-a-configuration /openapi/cortex_swagger.json delete /api/v1/apiiro/configuration/{alias} # Delete all configurations Source: https://docs.cortex.io/api/rest/apiiro-api/delete-all-configurations /openapi/cortex_swagger.json delete /api/v1/apiiro/configurations # Retrieve a configuration Source: https://docs.cortex.io/api/rest/apiiro-api/retrieve-a-configuration /openapi/cortex_swagger.json get /api/v1/apiiro/configuration/{alias} # Retrieve configurations Source: https://docs.cortex.io/api/rest/apiiro-api/retrieve-configurations /openapi/cortex_swagger.json get /api/v1/apiiro/configurations # Retrieve default configuration Source: https://docs.cortex.io/api/rest/apiiro-api/retrieve-default-configuration /openapi/cortex_swagger.json get /api/v1/apiiro/default-configuration # Update a configuration Source: https://docs.cortex.io/api/rest/apiiro-api/update-a-configuration /openapi/cortex_swagger.json put /api/v1/apiiro/configuration/{alias} WARNING: Updating aliases for configurations or changing the default configuration could cause entity YAMLs that use this integration to break. # Validate a configuration Source: https://docs.cortex.io/api/rest/apiiro-api/validate-a-configuration /openapi/cortex_swagger.json post /api/v1/apiiro/configuration/validate/{alias} # Validate all configurations Source: https://docs.cortex.io/api/rest/apiiro-api/validate-all-configurations /openapi/cortex_swagger.json post /api/v1/apiiro/configuration/validate # Add a single configuration Source: https://docs.cortex.io/api/rest/argocd-api/add-a-single-configuration /openapi/cortex_swagger.json post /api/v1/argocd/configuration # Add multiple configurations Source: https://docs.cortex.io/api/rest/argocd-api/add-multiple-configurations /openapi/cortex_swagger.json post /api/v1/argocd/configurations # Delete a configuration Source: https://docs.cortex.io/api/rest/argocd-api/delete-a-configuration /openapi/cortex_swagger.json delete /api/v1/argocd/configuration/{alias} # Delete all configurations Source: https://docs.cortex.io/api/rest/argocd-api/delete-all-configurations /openapi/cortex_swagger.json delete /api/v1/argocd/configurations # Retrieve a configuration Source: https://docs.cortex.io/api/rest/argocd-api/retrieve-a-configuration /openapi/cortex_swagger.json get /api/v1/argocd/configuration/{alias} # Retrieve configurations Source: https://docs.cortex.io/api/rest/argocd-api/retrieve-configurations /openapi/cortex_swagger.json get /api/v1/argocd/configurations # Retrieve default configuration Source: https://docs.cortex.io/api/rest/argocd-api/retrieve-default-configuration /openapi/cortex_swagger.json get /api/v1/argocd/default-configuration # Update a configuration Source: https://docs.cortex.io/api/rest/argocd-api/update-a-configuration /openapi/cortex_swagger.json put /api/v1/argocd/configuration/{alias} WARNING: Updating aliases for configurations or changing the default configuration could cause entity YAMLs that use this integration to break. # Validate a configuration Source: https://docs.cortex.io/api/rest/argocd-api/validate-a-configuration /openapi/cortex_swagger.json post /api/v1/argocd/configuration/validate/{alias} # Validate all configurations Source: https://docs.cortex.io/api/rest/argocd-api/validate-all-configurations /openapi/cortex_swagger.json post /api/v1/argocd/configuration/validate # Audit Logs Source: https://docs.cortex.io/api/rest/audit-logs Use these operations to interact with [audit logs](/configure/settings/audit-logs) in Cortex. ### Required permissions Your API token must have the `View audit logs` permission. > **[Retrieve audit logs](/api/rest/audit-logs/retrieve-audit-logs)** > > `GET /api/v1/audit-logs` # Retrieve audit logs Source: https://docs.cortex.io/api/rest/audit-logs/retrieve-audit-logs /openapi/cortex_swagger.json get /api/v1/audit-logs Note: To see the complete list of possible values, please reference the available filter options for [audit logs under Settings in the app](https://app.getcortexapp.com/admin/settings/audit-logs). API key must have the `View audit logs` permission. # Add a single configuration Source: https://docs.cortex.io/api/rest/aws-api/add-a-single-configuration /openapi/cortex_swagger.json post /api/v1/aws/configurations # Delete a configuration Source: https://docs.cortex.io/api/rest/aws-api/delete-a-configuration /openapi/cortex_swagger.json delete /api/v1/aws/configurations/{accountId} # Delete all configurations Source: https://docs.cortex.io/api/rest/aws-api/delete-all-configurations /openapi/cortex_swagger.json delete /api/v1/aws/configurations # Get AWS resource details for an entity Source: https://docs.cortex.io/api/rest/aws-api/get-aws-resource-details-for-an-entity /openapi/cortex_swagger.json get /api/v1/catalog/{tagOrId}/aws Returns all cached AWS resource details for the specified entity. This endpoint serves cached data only and does not make live AWS API calls. # List AWS types Source: https://docs.cortex.io/api/rest/aws-api/list-aws-types /openapi/cortex_swagger.json get /api/v1/aws/types # Retrieve a configuration Source: https://docs.cortex.io/api/rest/aws-api/retrieve-a-configuration /openapi/cortex_swagger.json get /api/v1/aws/configurations/{accountId} # Retrieve configurations Source: https://docs.cortex.io/api/rest/aws-api/retrieve-configurations /openapi/cortex_swagger.json get /api/v1/aws/configurations # Update configurations Source: https://docs.cortex.io/api/rest/aws-api/update-configurations /openapi/cortex_swagger.json put /api/v1/aws/configurations # Update configured AWS types Source: https://docs.cortex.io/api/rest/aws-api/update-configured-aws-types /openapi/cortex_swagger.json put /api/v1/aws/types # Validate a configuration Source: https://docs.cortex.io/api/rest/aws-api/validate-a-configuration /openapi/cortex_swagger.json post /api/v1/aws/configurations/validate/{accountId} # Validate all configurations Source: https://docs.cortex.io/api/rest/aws-api/validate-all-configurations /openapi/cortex_swagger.json post /api/v1/aws/configurations/all/validate # Add a configuration Source: https://docs.cortex.io/api/rest/azure-active-directory-entra-id-api/add-a-configuration /openapi/cortex_swagger.json post /api/v1/active-directory/configuration # Delete a configuration Source: https://docs.cortex.io/api/rest/azure-active-directory-entra-id-api/delete-a-configuration /openapi/cortex_swagger.json delete /api/v1/active-directory/configurations # Retrieve a configuration Source: https://docs.cortex.io/api/rest/azure-active-directory-entra-id-api/retrieve-a-configuration /openapi/cortex_swagger.json get /api/v1/active-directory/default-configuration # Update the existing configuration Source: https://docs.cortex.io/api/rest/azure-active-directory-entra-id-api/update-the-existing-configuration /openapi/cortex_swagger.json put /api/v1/active-directory/configuration # Validate a configuration Source: https://docs.cortex.io/api/rest/azure-active-directory-entra-id-api/validate-a-configuration /openapi/cortex_swagger.json post /api/v1/active-directory/configuration/validate # Add a single configuration Source: https://docs.cortex.io/api/rest/azure-devops-api/add-a-single-configuration /openapi/cortex_swagger.json post /api/v1/azure-devops/configuration # Add multiple configurations Source: https://docs.cortex.io/api/rest/azure-devops-api/add-multiple-configurations /openapi/cortex_swagger.json post /api/v1/azure-devops/configurations # Delete a configuration Source: https://docs.cortex.io/api/rest/azure-devops-api/delete-a-configuration /openapi/cortex_swagger.json delete /api/v1/azure-devops/configuration/{alias} # Delete all configurations Source: https://docs.cortex.io/api/rest/azure-devops-api/delete-all-configurations /openapi/cortex_swagger.json delete /api/v1/azure-devops/configurations # Retrieve a configuration Source: https://docs.cortex.io/api/rest/azure-devops-api/retrieve-a-configuration /openapi/cortex_swagger.json get /api/v1/azure-devops/configuration/{alias} # Retrieve configurations Source: https://docs.cortex.io/api/rest/azure-devops-api/retrieve-configurations /openapi/cortex_swagger.json get /api/v1/azure-devops/configurations # Retrieve default configuration Source: https://docs.cortex.io/api/rest/azure-devops-api/retrieve-default-configuration /openapi/cortex_swagger.json get /api/v1/azure-devops/default-configuration # Update a configuration Source: https://docs.cortex.io/api/rest/azure-devops-api/update-a-configuration /openapi/cortex_swagger.json put /api/v1/azure-devops/configuration/{alias} WARNING: Updating aliases for configurations or changing the default configuration could cause entity YAMLs that use this integration to break. # Validate a configuration Source: https://docs.cortex.io/api/rest/azure-devops-api/validate-a-configuration /openapi/cortex_swagger.json post /api/v1/azure-devops/configuration/validate/{alias} # Validate all configurations Source: https://docs.cortex.io/api/rest/azure-devops-api/validate-all-configurations /openapi/cortex_swagger.json post /api/v1/azure-devops/configuration/validate # Add a single configuration Source: https://docs.cortex.io/api/rest/azure-resources-api/add-a-single-configuration /openapi/cortex_swagger.json post /api/v1/azure-resources/configuration # Add multiple configurations Source: https://docs.cortex.io/api/rest/azure-resources-api/add-multiple-configurations /openapi/cortex_swagger.json post /api/v1/azure-resources/configurations # Delete a configuration Source: https://docs.cortex.io/api/rest/azure-resources-api/delete-a-configuration /openapi/cortex_swagger.json delete /api/v1/azure-resources/configuration/{alias} # Delete all configurations Source: https://docs.cortex.io/api/rest/azure-resources-api/delete-all-configurations /openapi/cortex_swagger.json delete /api/v1/azure-resources/configurations # List Azure Resources types Source: https://docs.cortex.io/api/rest/azure-resources-api/list-azure-resources-types /openapi/cortex_swagger.json get /api/v1/azure-resources/types # Retrieve a configuration Source: https://docs.cortex.io/api/rest/azure-resources-api/retrieve-a-configuration /openapi/cortex_swagger.json get /api/v1/azure-resources/configuration/{alias} # Retrieve configurations Source: https://docs.cortex.io/api/rest/azure-resources-api/retrieve-configurations /openapi/cortex_swagger.json get /api/v1/azure-resources/configurations # Retrieve default configuration Source: https://docs.cortex.io/api/rest/azure-resources-api/retrieve-default-configuration /openapi/cortex_swagger.json get /api/v1/azure-resources/default-configuration # Update a configuration Source: https://docs.cortex.io/api/rest/azure-resources-api/update-a-configuration /openapi/cortex_swagger.json put /api/v1/azure-resources/configuration/{alias} WARNING: Updating aliases for configurations or changing the default configuration could cause entity YAMLs that use this integration to break. # Update configured Azure Resources types Source: https://docs.cortex.io/api/rest/azure-resources-api/update-configured-azure-resources-types /openapi/cortex_swagger.json put /api/v1/azure-resources/types # Validate a configuration Source: https://docs.cortex.io/api/rest/azure-resources-api/validate-a-configuration /openapi/cortex_swagger.json post /api/v1/azure-resources/configuration/validate/{alias} # Validate all configurations Source: https://docs.cortex.io/api/rest/azure-resources-api/validate-all-configurations /openapi/cortex_swagger.json post /api/v1/azure-resources/configuration/validate # Add a configuration Source: https://docs.cortex.io/api/rest/bamboohr-api/add-a-configuration /openapi/cortex_swagger.json post /api/v1/bamboohr/configuration # Delete a configuration Source: https://docs.cortex.io/api/rest/bamboohr-api/delete-a-configuration /openapi/cortex_swagger.json delete /api/v1/bamboohr/configurations # Retrieve a configuration Source: https://docs.cortex.io/api/rest/bamboohr-api/retrieve-a-configuration /openapi/cortex_swagger.json get /api/v1/bamboohr/default-configuration # Update the existing configuration Source: https://docs.cortex.io/api/rest/bamboohr-api/update-the-existing-configuration /openapi/cortex_swagger.json put /api/v1/bamboohr/configuration # Validate a configuration Source: https://docs.cortex.io/api/rest/bamboohr-api/validate-a-configuration /openapi/cortex_swagger.json post /api/v1/bamboohr/configuration/validate # Add a single configuration Source: https://docs.cortex.io/api/rest/bitbucket-api/add-a-single-configuration /openapi/cortex_swagger.json post /api/v1/bitbucket/configuration # Add multiple configurations Source: https://docs.cortex.io/api/rest/bitbucket-api/add-multiple-configurations /openapi/cortex_swagger.json post /api/v1/bitbucket/configurations # Delete a configuration Source: https://docs.cortex.io/api/rest/bitbucket-api/delete-a-configuration /openapi/cortex_swagger.json delete /api/v1/bitbucket/configuration/{alias} # Delete all configurations Source: https://docs.cortex.io/api/rest/bitbucket-api/delete-all-configurations /openapi/cortex_swagger.json delete /api/v1/bitbucket/configurations # Retrieve a configuration Source: https://docs.cortex.io/api/rest/bitbucket-api/retrieve-a-configuration /openapi/cortex_swagger.json get /api/v1/bitbucket/configuration/{alias} # Retrieve configurations Source: https://docs.cortex.io/api/rest/bitbucket-api/retrieve-configurations /openapi/cortex_swagger.json get /api/v1/bitbucket/configurations # Retrieve default configuration Source: https://docs.cortex.io/api/rest/bitbucket-api/retrieve-default-configuration /openapi/cortex_swagger.json get /api/v1/bitbucket/default-configuration # Update a configuration Source: https://docs.cortex.io/api/rest/bitbucket-api/update-a-configuration /openapi/cortex_swagger.json put /api/v1/bitbucket/configuration/{alias} WARNING: Updating aliases for configurations or changing the default configuration could cause entity YAMLs that use this integration to break. # Validate a configuration Source: https://docs.cortex.io/api/rest/bitbucket-api/validate-a-configuration /openapi/cortex_swagger.json post /api/v1/bitbucket/configuration/validate/{alias} # Validate all configurations Source: https://docs.cortex.io/api/rest/bitbucket-api/validate-all-configurations /openapi/cortex_swagger.json post /api/v1/bitbucket/configuration/validate # Add a configuration Source: https://docs.cortex.io/api/rest/bugsnag-api/add-a-configuration /openapi/cortex_swagger.json post /api/v1/bugsnag/configuration # Delete a configuration Source: https://docs.cortex.io/api/rest/bugsnag-api/delete-a-configuration /openapi/cortex_swagger.json delete /api/v1/bugsnag/configurations # Retrieve a configuration Source: https://docs.cortex.io/api/rest/bugsnag-api/retrieve-a-configuration /openapi/cortex_swagger.json get /api/v1/bugsnag/default-configuration # Update the existing configuration Source: https://docs.cortex.io/api/rest/bugsnag-api/update-the-existing-configuration /openapi/cortex_swagger.json put /api/v1/bugsnag/configuration # Validate a configuration Source: https://docs.cortex.io/api/rest/bugsnag-api/validate-a-configuration /openapi/cortex_swagger.json post /api/v1/bugsnag/configuration/validate # Add a configuration Source: https://docs.cortex.io/api/rest/buildkite-api/add-a-configuration /openapi/cortex_swagger.json post /api/v1/buildkite/configuration # Delete a configuration Source: https://docs.cortex.io/api/rest/buildkite-api/delete-a-configuration /openapi/cortex_swagger.json delete /api/v1/buildkite/configurations # Retrieve a configuration Source: https://docs.cortex.io/api/rest/buildkite-api/retrieve-a-configuration /openapi/cortex_swagger.json get /api/v1/buildkite/default-configuration # Update the existing configuration Source: https://docs.cortex.io/api/rest/buildkite-api/update-the-existing-configuration /openapi/cortex_swagger.json put /api/v1/buildkite/configuration # Validate a configuration Source: https://docs.cortex.io/api/rest/buildkite-api/validate-a-configuration /openapi/cortex_swagger.json post /api/v1/buildkite/configuration/validate # Catalog Entities Source: https://docs.cortex.io/api/rest/catalog-entities Use these operations to interact with [entities](/ingesting-data-into-cortex/entities-overview/entities) in Cortex. To see additional API operations specific to team entities, see the [Teams API page](/api/rest/teams). ### Required permissions * Edit entities: Your API key must have the `Edit entities` permission. * Archive entities: Your API key must have the `Archive entities` permission. * Delete entities: Your API key must have `Delete entities` permission. ## Operations > **[List entities](/api/rest/catalog-entities/list-entities)** > > `GET /api/v1/catalog` > **[Search entities](/api/rest/catalog-entities/search-entities)** > > `GET /api/v1/catalog/search` > **[List entity descriptors](/api/rest/catalog-entities/list-entity-descriptors)** > > `GET /api/v1/catalog/descriptors` > **[Retrieve entity details](/api/rest/catalog-entities/retrieve-entity-details)** > > `GET /api/v1/catalog/{tagOrId}` > **[Retrieve most recent GitOps log for entity](/api/rest/catalog-entities/retrieve-most-recent-gitops-log-for-entity)** > > `GET /api/v1/catalog/{tagOrId}/gitops-logs` > **[Retrieve entity descriptor](/api/rest/catalog-entities/retrieve-entity-descriptor)** > > `GET /api/v1/catalog/{tagOrId}/openapi` > **[Retrieve entity Scorecard scores](/api/rest/catalog-entities/retrieve-entity-scorecard-scores)** > > `GET /api/v1/catalog/{tagOrId}/scorecards` > **[Create or update entity](/api/rest/catalog-entities/create-or-update-entity)** > > `POST /api/v1/open-api` > **[Archive an entity](/api/rest/catalog-entities/archive-an-entity)** > > `PUT /api/v1/catalog/{tagOrId}/archive` > **[Unarchive an entity](/api/rest/catalog-entities/unarchive-an-entity)** > > `PUT /api/v1/catalog/{tagOrId}/unarchive` > **[Create or patch entity](/api/rest/catalog-entities/create-or-patch-entity)** > > `PATCH /api/v1/open-api` > **[Delete entity](/api/rest/catalog-entities/delete-entity)** > > `DELETE /api/v1/catalog/{tagOrId}` > **[Delete entities by ID](/api/rest/catalog-entities/delete-entities-by-id)** > > `DELETE /api/v1/catalog` > **[Get Kubernetes resource details for an entity](/api/rest/kubernetes-api/get-kubernetes-resource-details-for-an-entity)** > > `GET /api/v1/catalog/{tagOrId}/k8s` # Archive an entity Source: https://docs.cortex.io/api/rest/catalog-entities/archive-an-entity /openapi/cortex_swagger.json put /api/v1/catalog/{tagOrId}/archive # Create or patch entity Source: https://docs.cortex.io/api/rest/catalog-entities/create-or-patch-entity /openapi/cortex_swagger.json patch /api/v1/open-api Creates or updates an entity using OpenAPI. If the YAML refers to an entity that already exists (as referenced by the `x-cortex-tag`), this API will merge the specified changes into the existing entity. # Create or update entity Source: https://docs.cortex.io/api/rest/catalog-entities/create-or-update-entity /openapi/cortex_swagger.json post /api/v1/open-api Create a catalog entity using a descriptor YAML. By default (UPSERT mode), if the entity already exists (as referenced by the `x-cortex-tag`), this API will update the existing entity. In CREATE mode, the API will fail if the entity already exists. # Delete entities by ID Source: https://docs.cortex.io/api/rest/catalog-entities/delete-entities-by-id /openapi/cortex_swagger.json delete /api/v1/catalog Deletes the entities with the given IDs. # Delete entity Source: https://docs.cortex.io/api/rest/catalog-entities/delete-entity /openapi/cortex_swagger.json delete /api/v1/catalog/{tagOrId} # List entities Source: https://docs.cortex.io/api/rest/catalog-entities/list-entities /openapi/cortex_swagger.json get /api/v1/catalog List all entities across the Service, Resource and Domain Catalogs. This API returns summary data for each entity, so refer to the retrieve entity method to lookup more details for a single entity. # List entity descriptors Source: https://docs.cortex.io/api/rest/catalog-entities/list-entity-descriptors /openapi/cortex_swagger.json get /api/v1/catalog/descriptors List entity descriptors The descriptors do not include objects (e.g. custom data, dependencies, etc) defined via the API # Retrieve entity descriptor Source: https://docs.cortex.io/api/rest/catalog-entities/retrieve-entity-descriptor /openapi/cortex_swagger.json get /api/v1/catalog/{tagOrId}/openapi Retrieve entity descriptor The descriptor does not include objects (e.g. custom data, dependencies, etc) defined via the API # Retrieve entity details Source: https://docs.cortex.io/api/rest/catalog-entities/retrieve-entity-details /openapi/cortex_swagger.json get /api/v1/catalog/{tagOrId} # Retrieve entity Scorecard scores Source: https://docs.cortex.io/api/rest/catalog-entities/retrieve-entity-scorecard-scores /openapi/cortex_swagger.json get /api/v1/catalog/{tagOrId}/scorecards # Retrieve entity verifications Source: https://docs.cortex.io/api/rest/catalog-entities/retrieve-entity-verifications /openapi/cortex_swagger.json get /api/v1/catalog/{tagOrId}/verifications Returns one entry per verification period the entity is in scope for, including periods the entity has not been verified for yet. # Retrieve most recent GitOps log for entity Source: https://docs.cortex.io/api/rest/catalog-entities/retrieve-most-recent-gitops-log-for-entity /openapi/cortex_swagger.json get /api/v1/catalog/{tagOrId}/gitops-logs # Search entities Source: https://docs.cortex.io/api/rest/catalog-entities/search-entities /openapi/cortex_swagger.json get /api/v1/catalog/search Relevance-ranked catalog search. Returns a lean, hydrated result set scoped by query and/or filters. # Unarchive an entity Source: https://docs.cortex.io/api/rest/catalog-entities/unarchive-an-entity /openapi/cortex_swagger.json put /api/v1/catalog/{tagOrId}/unarchive # Verify an entity for a verification period Source: https://docs.cortex.io/api/rest/catalog-entities/verify-an-entity-for-a-verification-period /openapi/cortex_swagger.json put /api/v1/catalog/{tagOrId}/verifications/{periodCid} Records the caller's answer for one entity in one verification period. The period must be open, and the caller must own the entity -- unless it is a global API key granted the "Verify any entity" permission, for which ownership is waived. # Catalogs Source: https://docs.cortex.io/api/rest/catalogs Use these operations to interact with [catalogs](/ingesting-data-into-cortex/catalogs/viewing-catalogs) in Cortex. ### Required permissions * View catalogs: Your API key must have the `View catalogs` permission. * Edit catalogs: Your API key must have the `Edit catalogs` permission. ## Operations > **[List catalogs](/api/rest/catalogs/list-catalogs)** > > `GET /api/v1/catalog-pages` > **[Create or replace a catalog](/api/rest/catalogs/create-or-replace-a-catalog)** > > `POST /api/v1/catalog-pages` > **[Get catalog](/api/rest/catalogs/get-catalog)** > > `GET /api/v1/catalog-pages/{slug}` > **[Delete catalog](/api/rest/catalogs/delete-catalog)** > > `DELETE /api/v1/catalog-pages/{slug}` # Create or replace a catalog Source: https://docs.cortex.io/api/rest/catalogs/create-or-replace-a-catalog /openapi/cortex_swagger.json post /api/v1/catalog-pages Creates a catalog, or replaces the existing one with the same slug. API key must have the `Edit catalogs` permission. # Delete catalog Source: https://docs.cortex.io/api/rest/catalogs/delete-catalog /openapi/cortex_swagger.json delete /api/v1/catalog-pages/{slug} # Get catalog Source: https://docs.cortex.io/api/rest/catalogs/get-catalog /openapi/cortex_swagger.json get /api/v1/catalog-pages/{slug} Retrieves a single catalog by slug. API key must have the `View catalogs` permission. # List catalogs Source: https://docs.cortex.io/api/rest/catalogs/list-catalogs /openapi/cortex_swagger.json get /api/v1/catalog-pages Retrieves a list of catalogs. API key must have the `View catalogs` permission. # Add a configuration Source: https://docs.cortex.io/api/rest/checkmarx-sast-api/add-a-configuration /openapi/cortex_swagger.json post /api/v1/checkmarx/sast/configuration # Delete a configuration Source: https://docs.cortex.io/api/rest/checkmarx-sast-api/delete-a-configuration /openapi/cortex_swagger.json delete /api/v1/checkmarx/sast/configurations # Retrieve a configuration Source: https://docs.cortex.io/api/rest/checkmarx-sast-api/retrieve-a-configuration /openapi/cortex_swagger.json get /api/v1/checkmarx/sast/default-configuration # Update the existing configuration Source: https://docs.cortex.io/api/rest/checkmarx-sast-api/update-the-existing-configuration /openapi/cortex_swagger.json put /api/v1/checkmarx/sast/configuration # Validate a configuration Source: https://docs.cortex.io/api/rest/checkmarx-sast-api/validate-a-configuration /openapi/cortex_swagger.json post /api/v1/checkmarx/sast/configuration/validate # Add a single configuration Source: https://docs.cortex.io/api/rest/circleci-api/add-a-single-configuration /openapi/cortex_swagger.json post /api/v1/circleci/configuration # Add multiple configurations Source: https://docs.cortex.io/api/rest/circleci-api/add-multiple-configurations /openapi/cortex_swagger.json post /api/v1/circleci/configurations # Delete a configuration Source: https://docs.cortex.io/api/rest/circleci-api/delete-a-configuration /openapi/cortex_swagger.json delete /api/v1/circleci/configuration/{alias} # Delete all configurations Source: https://docs.cortex.io/api/rest/circleci-api/delete-all-configurations /openapi/cortex_swagger.json delete /api/v1/circleci/configurations # Retrieve a configuration Source: https://docs.cortex.io/api/rest/circleci-api/retrieve-a-configuration /openapi/cortex_swagger.json get /api/v1/circleci/configuration/{alias} # Retrieve configurations Source: https://docs.cortex.io/api/rest/circleci-api/retrieve-configurations /openapi/cortex_swagger.json get /api/v1/circleci/configurations # Retrieve default configuration Source: https://docs.cortex.io/api/rest/circleci-api/retrieve-default-configuration /openapi/cortex_swagger.json get /api/v1/circleci/default-configuration # Update a configuration Source: https://docs.cortex.io/api/rest/circleci-api/update-a-configuration /openapi/cortex_swagger.json put /api/v1/circleci/configuration/{alias} WARNING: Updating aliases for configurations or changing the default configuration could cause entity YAMLs that use this integration to break. # Validate a configuration Source: https://docs.cortex.io/api/rest/circleci-api/validate-a-configuration /openapi/cortex_swagger.json post /api/v1/circleci/configuration/validate/{alias} # Validate all configurations Source: https://docs.cortex.io/api/rest/circleci-api/validate-all-configurations /openapi/cortex_swagger.json post /api/v1/circleci/configuration/validate # Add a configuration Source: https://docs.cortex.io/api/rest/clickup-api/add-a-configuration /openapi/cortex_swagger.json post /api/v1/clickup/configuration # Delete a configuration Source: https://docs.cortex.io/api/rest/clickup-api/delete-a-configuration /openapi/cortex_swagger.json delete /api/v1/clickup/configurations # Retrieve a configuration Source: https://docs.cortex.io/api/rest/clickup-api/retrieve-a-configuration /openapi/cortex_swagger.json get /api/v1/clickup/default-configuration # Update the existing configuration Source: https://docs.cortex.io/api/rest/clickup-api/update-the-existing-configuration /openapi/cortex_swagger.json put /api/v1/clickup/configuration # Validate a configuration Source: https://docs.cortex.io/api/rest/clickup-api/validate-a-configuration /openapi/cortex_swagger.json post /api/v1/clickup/configuration/validate # Add a configuration Source: https://docs.cortex.io/api/rest/codecov-api/add-a-configuration /openapi/cortex_swagger.json post /api/v1/codecov/configuration # Delete a configuration Source: https://docs.cortex.io/api/rest/codecov-api/delete-a-configuration /openapi/cortex_swagger.json delete /api/v1/codecov/configurations # Retrieve a configuration Source: https://docs.cortex.io/api/rest/codecov-api/retrieve-a-configuration /openapi/cortex_swagger.json get /api/v1/codecov/default-configuration # Update the existing configuration Source: https://docs.cortex.io/api/rest/codecov-api/update-the-existing-configuration /openapi/cortex_swagger.json put /api/v1/codecov/configuration # Validate a configuration Source: https://docs.cortex.io/api/rest/codecov-api/validate-a-configuration /openapi/cortex_swagger.json post /api/v1/codecov/configuration/validate # Add a single configuration Source: https://docs.cortex.io/api/rest/coralogix-api/add-a-single-configuration /openapi/cortex_swagger.json post /api/v1/coralogix/configuration # Add multiple configurations Source: https://docs.cortex.io/api/rest/coralogix-api/add-multiple-configurations /openapi/cortex_swagger.json post /api/v1/coralogix/configurations # Delete a configuration Source: https://docs.cortex.io/api/rest/coralogix-api/delete-a-configuration /openapi/cortex_swagger.json delete /api/v1/coralogix/configuration/{alias} # Delete all configurations Source: https://docs.cortex.io/api/rest/coralogix-api/delete-all-configurations /openapi/cortex_swagger.json delete /api/v1/coralogix/configurations # Retrieve a configuration Source: https://docs.cortex.io/api/rest/coralogix-api/retrieve-a-configuration /openapi/cortex_swagger.json get /api/v1/coralogix/configuration/{alias} # Retrieve configurations Source: https://docs.cortex.io/api/rest/coralogix-api/retrieve-configurations /openapi/cortex_swagger.json get /api/v1/coralogix/configurations # Retrieve default configuration Source: https://docs.cortex.io/api/rest/coralogix-api/retrieve-default-configuration /openapi/cortex_swagger.json get /api/v1/coralogix/default-configuration # Update a configuration Source: https://docs.cortex.io/api/rest/coralogix-api/update-a-configuration /openapi/cortex_swagger.json put /api/v1/coralogix/configuration/{alias} WARNING: Updating aliases for configurations or changing the default configuration could cause entity YAMLs that use this integration to break. # Validate a configuration Source: https://docs.cortex.io/api/rest/coralogix-api/validate-a-configuration /openapi/cortex_swagger.json post /api/v1/coralogix/configuration/validate/{alias} # Validate all configurations Source: https://docs.cortex.io/api/rest/coralogix-api/validate-all-configurations /openapi/cortex_swagger.json post /api/v1/coralogix/configuration/validate # Custom Data Source: https://docs.cortex.io/api/rest/custom-data Use these operations to interact with [custom data](/ingesting-data-into-cortex/entities-overview/entities/custom-data) in Cortex. ### Required permissions Edit entities: Your API key must have the `Edit entities` permission. ## Operations > **[List custom data for entity](/api/rest/custom-data/list-custom-data-for-entity)** > > `GET /api/v1/catalog/{tagOrId}/custom-data` > **[Retrieve custom data for entity](/api/rest/custom-data-advanced/retrieve-custom-data-for-entity)** > > `GET /api/v1/catalog/custom-data` > **[Retrieve custom data for entity by key](/api/rest/custom-data/retrieve-custom-data-for-entity-by-key)** > > `GET /api/v1/catalog/{tagOrId}/custom-data/{key}` > **[Add custom data for entity](/api/rest/custom-data/add-custom-data-for-entity)** > > `POST /api/v1/catalog/{tagOrId}/custom-data` > **[Add custom data via webhook](/api/rest/custom-data/add-custom-data-via-webhook)** > > `POST /api/v1/custom-integrations/data/{uuid}` > **[Add custom data in bulk](/api/rest/custom-data/add-custom-data-in-bulk)** > > `PUT /api/v1/catalog/custom-data` > **[Delete custom data for entity](/api/rest/custom-data/delete-custom-data-for-entity)** > > `DELETE /api/v1/catalog/{tagOrId}/custom-data` > **[Delete custom data by key for entity](/api/rest/custom-data-advanced/delete-custom-data-by-key-for-entity)** > > `DELETE /api/v1/catalog/custom-data` # Add custom data for entity (advanced) Source: https://docs.cortex.io/api/rest/custom-data-advanced/add-custom-data-for-entity-advanced /openapi/cortex_swagger.json post /api/v1/catalog/custom-data # Delete custom data by key for entity Source: https://docs.cortex.io/api/rest/custom-data-advanced/delete-custom-data-by-key-for-entity /openapi/cortex_swagger.json delete /api/v1/catalog/custom-data Use this endpoint when attempting to delete custom data where the key contains non-alphanumeric characters. Otherwise, use the standard API under `Custom Data`. # Retrieve custom data for entity Source: https://docs.cortex.io/api/rest/custom-data-advanced/retrieve-custom-data-for-entity /openapi/cortex_swagger.json get /api/v1/catalog/custom-data Use this endpoint when attempting to delete custom data where the key contains non-alphanumeric characters. Otherwise, use the standard API under `Custom Data`. # Add custom data for entity Source: https://docs.cortex.io/api/rest/custom-data/add-custom-data-for-entity /openapi/cortex_swagger.json post /api/v1/catalog/{tagOrId}/custom-data # Add custom data in bulk Source: https://docs.cortex.io/api/rest/custom-data/add-custom-data-in-bulk /openapi/cortex_swagger.json put /api/v1/catalog/custom-data Add multiple key/values of custom data to multiple entities # Add custom data via webhook Source: https://docs.cortex.io/api/rest/custom-data/add-custom-data-via-webhook /openapi/cortex_swagger.json post /api/v1/custom-integrations/data/{uuid} Refer to the [Webhook section](/docs/reference/basics/custom-data#webhook) of the Custom Data docs for more information. This API is preconfigured in your workspace settings under Custom Integrations. The UUID corresponds to a custom data key, as well as a `jq` command that maps the data in this payload to an entity in your workspace. # Custom Data (Advanced) Source: https://docs.cortex.io/api/rest/custom-data/custom-data-advanced > **[Retrieve custom data for entity](/api/rest/custom-data-advanced/retrieve-custom-data-for-entity)** > > `GET /api/v1/catalog/custom-data` > **[Add custom data for entity (advanced)](/api/rest/custom-data-advanced/add-custom-data-for-entity-advanced)** > > `POST /api/v1/catalog/custom-data` > **[Delete custom data by key for entity](/api/rest/custom-data-advanced/delete-custom-data-by-key-for-entity)** > > `DELETE /api/v1/catalog/custom-data` # Delete custom data for entity Source: https://docs.cortex.io/api/rest/custom-data/delete-custom-data-for-entity /openapi/cortex_swagger.json delete /api/v1/catalog/{tagOrId}/custom-data # List custom data for entity Source: https://docs.cortex.io/api/rest/custom-data/list-custom-data-for-entity /openapi/cortex_swagger.json get /api/v1/catalog/{tagOrId}/custom-data # Retrieve custom data for entity by key Source: https://docs.cortex.io/api/rest/custom-data/retrieve-custom-data-for-entity-by-key /openapi/cortex_swagger.json get /api/v1/catalog/{tagOrId}/custom-data/{key} # Custom Events Source: https://docs.cortex.io/api/rest/custom-events Use these operations to interact with custom events in Cortex. ### Required permissions Edit entities: Your API key must have the `Edit entities` permission. ## Operations > **[List custom events for entity](/api/rest/custom-events/list-custom-events-for-entity)** > > `GET /api/v1/catalog/{tagOrId}/custom-events` > **[Retrieve custom event by UUID](/api/rest/custom-events/retrieve-custom-event-by-uuid)** > > `GET /api/v1/catalog/{tagOrId}/custom-events/{uuid}` > **[Create custom event for entity](/api/rest/custom-events/create-custom-event-for-entity)** > > `POST /api/v1/catalog/{tagOrId}/custom-events` > **[Update custom event by UUID](/api/rest/custom-events/update-custom-event-by-uuid)** > > `PUT /api/v1/catalog/{tagOrId}/custom-events/{uuid}` > **[Delete ALL custom events for an entity](/api/rest/custom-events/delete-all-custom-events-for-an-entity)** > > `DELETE /api/v1/catalog/{tagOrId}/custom-events` > **[Delete custom events by UUID](/api/rest/custom-events/delete-custom-events-by-uuid)** > > `DELETE /api/v1/catalog/{tagOrId}/custom-events/{uuid}` # Create custom event for entity Source: https://docs.cortex.io/api/rest/custom-events/create-custom-event-for-entity /openapi/cortex_swagger.json post /api/v1/catalog/{tagOrId}/custom-events # Delete ALL custom events for an entity Source: https://docs.cortex.io/api/rest/custom-events/delete-all-custom-events-for-an-entity /openapi/cortex_swagger.json delete /api/v1/catalog/{tagOrId}/custom-events # Delete custom events by UUID Source: https://docs.cortex.io/api/rest/custom-events/delete-custom-events-by-uuid /openapi/cortex_swagger.json delete /api/v1/catalog/{tagOrId}/custom-events/{uuid} # List custom events for entity Source: https://docs.cortex.io/api/rest/custom-events/list-custom-events-for-entity /openapi/cortex_swagger.json get /api/v1/catalog/{tagOrId}/custom-events # Retrieve custom event by UUID Source: https://docs.cortex.io/api/rest/custom-events/retrieve-custom-event-by-uuid /openapi/cortex_swagger.json get /api/v1/catalog/{tagOrId}/custom-events/{uuid} # Update custom event by UUID Source: https://docs.cortex.io/api/rest/custom-events/update-custom-event-by-uuid /openapi/cortex_swagger.json put /api/v1/catalog/{tagOrId}/custom-events/{uuid} # Custom Metrics Source: https://docs.cortex.io/api/rest/custom-metrics Use these operations to interact with [custom metrics](/improve/eng-intelligence/custom-metrics) in Cortex Eng Intelligence. ### Required permissions The permission your API key needs depends on the operation: * To list or retrieve custom metric definitions, your API key must have the `View Eng Intelligence` permission. Draft metrics also require the `Configure Eng Intelligence custom metrics` permission. * To create, update, or delete custom metric definitions, your API key must have the `Configure Eng Intelligence custom metrics` permission. * To retrieve, add, or delete data points, your API key must have the `Manage Eng Intelligence custom metrics data via API` permission. ## Operations > **[List custom metric definitions](/api/rest/custom-metrics/list-custom-metric-definitions)** > > `GET /api/v1/eng-intel/custom-metrics` > **[Retrieve a custom metric definition](/api/rest/custom-metrics/retrieve-a-custom-metric-definition)** > > `GET /api/v1/eng-intel/custom-metrics/{customMetricKey}` > **[Create a custom metric definition](/api/rest/custom-metrics/create-a-custom-metric-definition)** > > `POST /api/v1/eng-intel/custom-metrics` > **[Update a custom metric definition](/api/rest/custom-metrics/update-a-custom-metric-definition)** > > `PUT /api/v1/eng-intel/custom-metrics/{customMetricKey}` > **[Delete a custom metric definition](/api/rest/custom-metrics/delete-a-custom-metric-definition)** > > `DELETE /api/v1/eng-intel/custom-metrics/{customMetricKey}` > **[Retrieve custom metrics data points](/api/rest/custom-metrics/retrieve-custom-metrics-data-points)** > > `GET /api/v1/eng-intel/custom-metrics/{customMetricKey}/entity/{tagOrId}` > **[Add custom metrics data point](/api/rest/custom-metrics/add-custom-metrics-data-point)** > > `POST /api/v1/eng-intel/custom-metrics/{customMetricKey}/entity/{tagOrId}` > **[Add custom metrics data points in bulk](/api/rest/custom-metrics/add-custom-metrics-data-points-in-bulk)** > > `POST /api/v1/eng-intel/custom-metrics/{customMetricKey}/entity/{tagOrId}/bulk` > **[Delete custom metrics data points](/api/rest/custom-metrics/delete-custom-metrics-data-points)** > > `DELETE /api/v1/eng-intel/custom-metrics/{customMetricKey}/entity/{tagOrId}` # Add custom metrics data point Source: https://docs.cortex.io/api/rest/custom-metrics/add-custom-metrics-data-point /openapi/cortex_swagger.json post /api/v1/eng-intel/custom-metrics/{customMetricKey}/entity/{tagOrId} Adds a single custom metric data point for entity. # Add custom metrics data points in bulk Source: https://docs.cortex.io/api/rest/custom-metrics/add-custom-metrics-data-points-in-bulk /openapi/cortex_swagger.json post /api/v1/eng-intel/custom-metrics/{customMetricKey}/entity/{tagOrId}/bulk Adds multiple custom metric data points for entity. # Create a custom metric definition Source: https://docs.cortex.io/api/rest/custom-metrics/create-a-custom-metric-definition /openapi/cortex_swagger.json post /api/v1/eng-intel/custom-metrics Defines a custom metric of type `PUBLIC_API`, which you then record data points against. The key cannot change after creation. API key must have the `Configure Eng Intelligence custom metrics` permission. # Delete a custom metric definition Source: https://docs.cortex.io/api/rest/custom-metrics/delete-a-custom-metric-definition /openapi/cortex_swagger.json delete /api/v1/eng-intel/custom-metrics/{customMetricKey} Removes the metric from Eng Intelligence. Its recorded data points stay out of reach, and creating the key again starts with no data. Only `PUBLIC_API` metrics can be deleted through the API. API key must have the `Configure Eng Intelligence custom metrics` permission. # Delete custom metrics data points Source: https://docs.cortex.io/api/rest/custom-metrics/delete-custom-metrics-data-points /openapi/cortex_swagger.json delete /api/v1/eng-intel/custom-metrics/{customMetricKey}/entity/{tagOrId} Deletes custom metric data points for entity. # List custom metric definitions Source: https://docs.cortex.io/api/rest/custom-metrics/list-custom-metric-definitions /openapi/cortex_swagger.json get /api/v1/eng-intel/custom-metrics Returns every custom metric defined in the workspace, sorted by key. API key must have the `View Eng Intelligence` permission. Draft metrics are included only when the key also has the `Configure Eng Intelligence custom metrics` permission. # Retrieve a custom metric definition Source: https://docs.cortex.io/api/rest/custom-metrics/retrieve-a-custom-metric-definition /openapi/cortex_swagger.json get /api/v1/eng-intel/custom-metrics/{customMetricKey} API key must have the `View Eng Intelligence` permission. A draft metric returns 404 unless the key also has the `Configure Eng Intelligence custom metrics` permission. # Retrieve custom metrics data points Source: https://docs.cortex.io/api/rest/custom-metrics/retrieve-custom-metrics-data-points /openapi/cortex_swagger.json get /api/v1/eng-intel/custom-metrics/{customMetricKey}/entity/{tagOrId} Lists all custom metrics data points for an entity # Update a custom metric definition Source: https://docs.cortex.io/api/rest/custom-metrics/update-a-custom-metric-definition /openapi/cortex_swagger.json put /api/v1/eng-intel/custom-metrics/{customMetricKey} Replaces the definition in full, so an omitted optional field is cleared. Only `PUBLIC_API` metrics can be updated through the API. API key must have the `Configure Eng Intelligence custom metrics` permission. # Add a single configuration Source: https://docs.cortex.io/api/rest/datadog-api/add-a-single-configuration /openapi/cortex_swagger.json post /api/v1/datadog/configuration # Add multiple configurations Source: https://docs.cortex.io/api/rest/datadog-api/add-multiple-configurations /openapi/cortex_swagger.json post /api/v1/datadog/configurations # Delete a configuration Source: https://docs.cortex.io/api/rest/datadog-api/delete-a-configuration /openapi/cortex_swagger.json delete /api/v1/datadog/configuration/{alias} # Delete all configurations Source: https://docs.cortex.io/api/rest/datadog-api/delete-all-configurations /openapi/cortex_swagger.json delete /api/v1/datadog/configurations # Retrieve a configuration Source: https://docs.cortex.io/api/rest/datadog-api/retrieve-a-configuration /openapi/cortex_swagger.json get /api/v1/datadog/configuration/{alias} # Retrieve configurations Source: https://docs.cortex.io/api/rest/datadog-api/retrieve-configurations /openapi/cortex_swagger.json get /api/v1/datadog/configurations # Retrieve default configuration Source: https://docs.cortex.io/api/rest/datadog-api/retrieve-default-configuration /openapi/cortex_swagger.json get /api/v1/datadog/default-configuration # Update a configuration Source: https://docs.cortex.io/api/rest/datadog-api/update-a-configuration /openapi/cortex_swagger.json put /api/v1/datadog/configuration/{alias} WARNING: Updating aliases for configurations or changing the default configuration could cause entity YAMLs that use this integration to break. # Validate a configuration Source: https://docs.cortex.io/api/rest/datadog-api/validate-a-configuration /openapi/cortex_swagger.json post /api/v1/datadog/configuration/validate/{alias} # Validate all configurations Source: https://docs.cortex.io/api/rest/datadog-api/validate-all-configurations /openapi/cortex_swagger.json post /api/v1/datadog/configuration/validate # Dependencies Source: https://docs.cortex.io/api/rest/dependencies Use these operations to interact with [dependencies](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/dependencies) in Cortex. ### Required permissions Your API key must have the `Edit entities` permission. ## Operations > **[Retrieve all dependencies for an entity](/api/rest/dependencies/retrieve-all-dependencies-for-an-entity)** > > `GET /api/v1/catalog/{callerTag}/dependencies` > **[Retrieve dependency between entities](/api/rest/dependencies/retrieve-dependency-between-entities)** > > `GET /api/v1/catalog/{callerTag}/dependencies/{calleeTag}` > **[Create dependency from entity](/api/rest/dependencies/create-dependency-from-entity)** > > `POST /api/v1/catalog/{callerTag}/dependencies/{calleeTag}` > **[Create or update dependencies in bulk](/api/rest/dependencies/create-or-update-dependencies-in-bulk)** > > `PUT /api/v1/catalog/dependencies` > **[Update dependency between entities](/api/rest/dependencies/update-dependency-between-entities)** > > `PUT /api/v1/catalog/{callerTag}/dependencies/{calleeTag}` > **[Delete dependency](/api/rest/dependencies/delete-dependency)** > > `DELETE /api/v1/catalog/{callerTag}/dependencies/{calleeTag}` > **[Delete dependencies from entity](/api/rest/dependencies/delete-dependencies-from-entity)** > > `DELETE /api/v1/catalog/{callerTag}/dependencies` > **[Delete dependencies in bulk](/api/rest/dependencies/delete-dependencies-in-bulk)** > > `DELETE /api/v1/catalog/dependencies` # Create dependency from entity Source: https://docs.cortex.io/api/rest/dependencies/create-dependency-from-entity /openapi/cortex_swagger.json post /api/v1/catalog/{callerTag}/dependencies/{calleeTag} # Create or update dependencies in bulk Source: https://docs.cortex.io/api/rest/dependencies/create-or-update-dependencies-in-bulk /openapi/cortex_swagger.json put /api/v1/catalog/dependencies This API allows you to create multiple dependencies for multiple entities at once. # Delete dependencies from entity Source: https://docs.cortex.io/api/rest/dependencies/delete-dependencies-from-entity /openapi/cortex_swagger.json delete /api/v1/catalog/{callerTag}/dependencies Deletes any outgoing dependencies from the entity. Note: this only deletes dependencies that were created via the API. # Delete dependencies in bulk Source: https://docs.cortex.io/api/rest/dependencies/delete-dependencies-in-bulk /openapi/cortex_swagger.json delete /api/v1/catalog/dependencies # Delete dependency Source: https://docs.cortex.io/api/rest/dependencies/delete-dependency /openapi/cortex_swagger.json delete /api/v1/catalog/{callerTag}/dependencies/{calleeTag} Deletes a single dependency edge between the `caller` and the `callee`. Note: This is only supported for edges created via the API. # Retrieve all dependencies for an entity Source: https://docs.cortex.io/api/rest/dependencies/retrieve-all-dependencies-for-an-entity /openapi/cortex_swagger.json get /api/v1/catalog/{callerTag}/dependencies # Retrieve dependency between entities Source: https://docs.cortex.io/api/rest/dependencies/retrieve-dependency-between-entities /openapi/cortex_swagger.json get /api/v1/catalog/{callerTag}/dependencies/{calleeTag} If a dependency exists between the `callee` and the `caller`, returns metadata about the edge. # Update dependency between entities Source: https://docs.cortex.io/api/rest/dependencies/update-dependency-between-entities /openapi/cortex_swagger.json put /api/v1/catalog/{callerTag}/dependencies/{calleeTag} If a dependency exists between two entities, replace the metadata with the payload. Note: This only supports dependencies created via the API. # Deploys Source: https://docs.cortex.io/api/rest/deploys Use these operations to interact with [deploys](/ingesting-data-into-cortex/entities-overview/entities/deploys) in Cortex. ### Required permissions Edit entities: Your API key must have the `Edit entities` permission. ## Operations > **[List deployments for entity](/api/rest/deploys/list-deployments-for-entity)** > > `GET /api/v1/catalog/{tagOrId}/deploys` > **[Add deployment for entity](/api/rest/deploys/add-deployment-for-entity)** > > `POST /api/v1/catalog/{tagOrId}/deploys` > **[Update deployment by UUID](/api/rest/deploys/update-deployment-by-uuid)** > > `PUT /api/v1/catalog/{tagOrId}/deploys/{uuid}` > **[Delete all deployments for all entities](/api/rest/deploys/delete-all-deployments-for-all-entities)** > > `DELETE /api/v1/catalog/deploys/all` > **[Delete deployments for entity](/api/rest/deploys/delete-deployments-for-entity)** > > `DELETE /api/v1/catalog/{tagOrId}/deploys` > **[Delete deployment by UUID](/api/rest/deploys/delete-deployment-by-uuid)** > > `DELETE /api/v1/catalog/{tagOrId}/deploys/{uuid}` > **[Delete deploys by filter](/api/rest/deploys/delete-deploys-by-filter)** > > `DELETE /api/v1/catalog/deploys` > **[List all distinct deploy environments for this tenant](/api/rest/deploys/list-all-distinct-deploy-environments-for-this-tenant)** > > `GET /api/v1/deploys/environments` > **[Search deployments across the tenant](/api/rest/deploys/search-deployments-across-the-tenant)** > > `GET /api/v1/deploys/search` # Add deployment for entity Source: https://docs.cortex.io/api/rest/deploys/add-deployment-for-entity /openapi/cortex_swagger.json post /api/v1/catalog/{tagOrId}/deploys # Delete all deployments for all entities Source: https://docs.cortex.io/api/rest/deploys/delete-all-deployments-for-all-entities /openapi/cortex_swagger.json delete /api/v1/catalog/deploys/all Dangerous endpoint that blows away deploys for all entities # Delete deployment by UUID Source: https://docs.cortex.io/api/rest/deploys/delete-deployment-by-uuid /openapi/cortex_swagger.json delete /api/v1/catalog/{tagOrId}/deploys/{uuid} # Delete deployments for entity Source: https://docs.cortex.io/api/rest/deploys/delete-deployments-for-entity /openapi/cortex_swagger.json delete /api/v1/catalog/{tagOrId}/deploys # Delete deploys by filter Source: https://docs.cortex.io/api/rest/deploys/delete-deploys-by-filter /openapi/cortex_swagger.json delete /api/v1/catalog/deploys Filter and delete deploys by SHA hash, environment, or type. Note that at least one of the filters need to be set. If looking to delete all deployments for an entity, use the `Delete all deploys for entity` endpoint instead. # List all distinct deploy environments for this tenant Source: https://docs.cortex.io/api/rest/deploys/list-all-distinct-deploy-environments-for-this-tenant /openapi/cortex_swagger.json get /api/v1/deploys/environments # List deployments for entity Source: https://docs.cortex.io/api/rest/deploys/list-deployments-for-entity /openapi/cortex_swagger.json get /api/v1/catalog/{tagOrId}/deploys # Search deployments across the tenant Source: https://docs.cortex.io/api/rest/deploys/search-deployments-across-the-tenant /openapi/cortex_swagger.json get /api/v1/deploys/search # Update deployment by UUID Source: https://docs.cortex.io/api/rest/deploys/update-deployment-by-uuid /openapi/cortex_swagger.json put /api/v1/catalog/{tagOrId}/deploys/{uuid} # Discovery Audit Source: https://docs.cortex.io/api/rest/discovery-audit Use these operations to interact with the [discovered entities list](/ingesting-data-into-cortex/entities-overview/entities/discovery-audit) in Cortex. ### Required permissions Your API key must have the `Configure discovery audit events` permission. ## Operations > **[Retrieve discovery audit report](/api/rest/discovery-audit/retrieve-discovery-audit-report)** > > `GET /api/v1/discovery-audit` # Retrieve discovery audit report Source: https://docs.cortex.io/api/rest/discovery-audit/retrieve-discovery-audit-report /openapi/cortex_swagger.json get /api/v1/discovery-audit This report shows you recent changes in your environment that aren't reflected in Cortex, including newly created repositories, services, and resources that we discover from your integrations or which were deleted in the environment but corresponding Cortex entities are still present. # Docs Source: https://docs.cortex.io/api/rest/docs Use these operations to interact with [external docs on entities](/ingesting-data-into-cortex/entities-overview/entities/external-docs) in Cortex. ### Required permissions Your API key must have the `Edit entities` permission. ## Operations > **[Retrieve OpenAPI docs for entity](/api/rest/docs/retrieve-openapi-docs-for-entity)** > > `GET /api/v1/catalog/{tagOrId}/documentation/openapi` > **[Update OpenAPI docs for entity](/api/rest/docs/update-openapi-docs-for-entity)** > > `PUT /api/v1/catalog/{tagOrId}/documentation/openapi` > **[Delete OpenAPI docs for entity](/api/rest/docs/delete-openapi-docs-for-entity)** > > `DELETE /api/v1/catalog/{tagOrId}/documentation/openapi` # Delete OpenAPI docs for entity Source: https://docs.cortex.io/api/rest/docs/delete-openapi-docs-for-entity /openapi/cortex_swagger.json delete /api/v1/catalog/{tagOrId}/documentation/openapi # Retrieve OpenAPI docs for entity Source: https://docs.cortex.io/api/rest/docs/retrieve-openapi-docs-for-entity /openapi/cortex_swagger.json get /api/v1/catalog/{tagOrId}/documentation/openapi # Update OpenAPI docs for entity Source: https://docs.cortex.io/api/rest/docs/update-openapi-docs-for-entity /openapi/cortex_swagger.json put /api/v1/catalog/{tagOrId}/documentation/openapi # Add a configuration Source: https://docs.cortex.io/api/rest/dynatrace-api/add-a-configuration /openapi/cortex_swagger.json post /api/v1/dynatrace/configuration # Delete a configuration Source: https://docs.cortex.io/api/rest/dynatrace-api/delete-a-configuration /openapi/cortex_swagger.json delete /api/v1/dynatrace/configurations # Retrieve a configuration Source: https://docs.cortex.io/api/rest/dynatrace-api/retrieve-a-configuration /openapi/cortex_swagger.json get /api/v1/dynatrace/default-configuration # Update the existing configuration Source: https://docs.cortex.io/api/rest/dynatrace-api/update-the-existing-configuration /openapi/cortex_swagger.json put /api/v1/dynatrace/configuration # Validate a configuration Source: https://docs.cortex.io/api/rest/dynatrace-api/validate-a-configuration /openapi/cortex_swagger.json post /api/v1/dynatrace/configuration/validate # Eng Intelligence: Metrics Source: https://docs.cortex.io/api/rest/eng-intel-metrics Use these operations to query aggregated metric data from [Eng Intelligence](/improve/eng-intelligence/eng-intelligence). You can group results and compare them across time periods. ### Required permissions Your API key must have the `View Dev Metrics` permission, and your workspace must have Eng Intelligence enabled. ### Query workflow 1. Call **List available engineering metric definitions** first. It returns the metric keys, data sources, and the `groupBy`, filter, and aggregation options that each metric supports. Use the exact keys from that response when you build a query. 2. Call **Execute point-in-time engineering metrics queries** to get aggregated metric values. You can group the results and compare them against a prior period. 3. To see the individual event records behind those values (pull requests, deployments, and so on), use the [Eng Intelligence: Trace operation](/api/rest/eng-intel-trace). Query results come back as `metadata` plus `rows`. Rows are positional, not keyed: the value at index `i` of each row corresponds to `metadata.columns[i]`. Queries are capped at a six-month date range, and trace queries at 500 rows per page. ## Operations > **[List available engineering metric definitions](/api/rest/eng-intel-metrics/list-available-engineering-metric-definitions)** > > `GET /api/v1/eng-intel/registry/metrics/definitions` > **[Execute point-in-time engineering metrics queries](/api/rest/eng-intel-metrics/execute-point-in-time-engineering-metrics-queries)** > > `POST /api/v1/eng-intel/metrics/point-in-time` # Execute point-in-time engineering metrics queries Source: https://docs.cortex.io/api/rest/eng-intel-metrics/execute-point-in-time-engineering-metrics-queries /openapi/cortex_swagger.json post /api/v1/eng-intel/metrics/point-in-time Query current metric values with optional period comparisons and flexible grouping. Supports batch queries for multiple metrics efficiently. # List available engineering metric definitions Source: https://docs.cortex.io/api/rest/eng-intel-metrics/list-available-engineering-metric-definitions /openapi/cortex_swagger.json get /api/v1/eng-intel/registry/metrics/definitions Discover all available engineering metrics and their metadata. Use this before querying metrics to understand what data is available and how to query it effectively. # Eng Intelligence: Trace Source: https://docs.cortex.io/api/rest/eng-intel-trace Use this operation to query individual event records from the engineering data sources behind [Eng Intelligence](/improve/eng-intelligence/eng-intelligence). You can filter, sort, and paginate the results. ### Required permissions Your API key must have the `View Dev Metrics` permission. ## Operations > **[Query raw trace events from engineering data sources](/api/rest/eng-intel-trace/query-raw-trace-events-from-engineering-data-sources)** > > `POST /api/v1/eng-intel/trace` # Query raw trace events from engineering data sources Source: https://docs.cortex.io/api/rest/eng-intel-trace/query-raw-trace-events-from-engineering-data-sources /openapi/cortex_swagger.json post /api/v1/eng-intel/trace Retrieve individual event records with flexible filtering, ordering, and pagination. Supports any engineering data source registered in the registry. # Eng Intelligence: User Labels Source: https://docs.cortex.io/api/rest/eng-intel-user-labels Use these operations to interact with [user labels](/improve/eng-intelligence/eng-intelligence#group-by-user-label) in Cortex Eng Intelligence. ### Required permissions Your API key must have the `Configure user labels` permission. ## Operations > **[List user labels](/api/rest/eng-intel-user-labels/list-user-labels)** > > `GET /api/v1/eng-intel/labels` > **[Retrieve user label](/api/rest/eng-intel-user-labels/retrieve-user-label)** > > `GET /api/v1/eng-intel/labels/{id}` > **[Update user label assignments](/api/rest/eng-intel-user-labels/update-user-label-assignments)** > > `POST /api/v1/eng-intel/labels/users` # List user labels Source: https://docs.cortex.io/api/rest/eng-intel-user-labels/list-user-labels /openapi/cortex_swagger.json get /api/v1/eng-intel/labels Retrieves a list of all available user labels. API key must have the `View Eng Intelligence` permission. # Retrieve user label Source: https://docs.cortex.io/api/rest/eng-intel-user-labels/retrieve-user-label /openapi/cortex_swagger.json get /api/v1/eng-intel/labels/{id} Get user label. API key must have the `View Eng Intelligence` permission. # Update user label assignments Source: https://docs.cortex.io/api/rest/eng-intel-user-labels/update-user-label-assignments /openapi/cortex_swagger.json post /api/v1/eng-intel/labels/users Assign user label values to user emails in bulk. API key must have the `Edit user labels` permission. # Get entity archival configuration Source: https://docs.cortex.io/api/rest/entity-archival/get-entity-archival-configuration /openapi/cortex_swagger.json get /api/v1/entity-archival-config Retrieve the workspace's archival settings: auto-archival from integrations and from GitOps, auto-archival of monorepo entities, and how many days an archived entity is kept before it is deleted. # Update entity archival configuration Source: https://docs.cortex.io/api/rest/entity-archival/update-entity-archival-configuration /openapi/cortex_swagger.json patch /api/v1/entity-archival-config Change the workspace's archival settings. Only the fields in the request change. Setting retentionDays requires automatic deletion to be enabled for the workspace. Requires the Edit Settings permission. # Entity Relationship Types Source: https://docs.cortex.io/api/rest/entity-relationship-types Use these operations to interact with [entity relationship types](/ingesting-data-into-cortex/entities-overview/entities/defining-relationship-types) in Cortex. ### Required permissions Create and Update Relationship Types: Your API key must have the `Edit entities` permission.\ Your tenant must also have the `Entity relationships` feature enabled. ### Operations > **[List relationship types](/api/rest/entity-relationship-types/list-relationship-types)** > > `GET /api/v1/relationship-types` > **[Create relationship type](/api/rest/entity-relationship-types/create-relationship-type)** > > `POST /api/v1/relationship-types` > **[Get a relationship type](/api/rest/entity-relationship-types/get-a-relationship-type)** > > `GET /api/v1/relationship-types/{relationshipTypeTag}` > **[Update relationship type](/api/rest/entity-relationship-types/update-relationship-type)** > > `PUT /api/v1/relationship-types/{relationshipTypeTag}` > **[Delete a relationship type](/api/rest/entity-relationship-types/delete-a-relationship-type)** > > `DELETE /api/v1/relationship-types/{relationshipTypeTag}` # Create relationship type Source: https://docs.cortex.io/api/rest/entity-relationship-types/create-relationship-type /openapi/cortex_swagger.json post /api/v1/relationship-types Create a relationship type # Delete a relationship type Source: https://docs.cortex.io/api/rest/entity-relationship-types/delete-a-relationship-type /openapi/cortex_swagger.json delete /api/v1/relationship-types/{relationshipTypeTag} Delete a relationship type # Get a relationship type Source: https://docs.cortex.io/api/rest/entity-relationship-types/get-a-relationship-type /openapi/cortex_swagger.json get /api/v1/relationship-types/{relationshipTypeTag} List details for a relationship type # List relationship types Source: https://docs.cortex.io/api/rest/entity-relationship-types/list-relationship-types /openapi/cortex_swagger.json get /api/v1/relationship-types List paginated relationship types # Update relationship type Source: https://docs.cortex.io/api/rest/entity-relationship-types/update-relationship-type /openapi/cortex_swagger.json put /api/v1/relationship-types/{relationshipTypeTag} Update relationship type # Entity Relationships Source: https://docs.cortex.io/api/rest/entity-relationships Use these operations to interact with [entity relationships](/ingesting-data-into-cortex/entities-overview/entities/defining-relationship-types) in Cortex. ### Required permissions Create and Update Relationships: Your API key must have the `Edit entities` permission.\ Your tenant must also have the `Entity relationships` feature enabled. ### Operations > **[List entity destinations for a relationship type](/api/rest/entity-relationships/list-entity-destinations-for-a-relationship-type)** > > `GET /api/v1/catalog/{tagOrId}/relationships/{relationshipTypeTag}/destinations` > **[Update direct entity destinations for a given entity](/api/rest/entity-relationships/update-direct-entity-destinations-for-a-given-entity)** > > `PUT /api/v1/catalog/{tagOrId}/relationships/{relationshipTypeTag}/destinations` > **[Add direct entity destinations for a given entity](/api/rest/entity-relationships/add-direct-entity-destinations-for-a-given-entity)** > > `POST /api/v1/catalog/{tagOrId}/relationships/{relationshipTypeTag}/destinations` > **[List entity sources for a relationship type](/api/rest/entity-relationships/list-entity-sources-for-a-relationship-type)** > > `GET /api/v1/catalog/{tagOrId}/relationships/{relationshipTypeTag}/sources` > **[Update direct entity sources for a given entity](/api/rest/entity-relationships/update-direct-entity-sources-for-a-given-entity)** > > `PUT /api/v1/catalog/{tagOrId}/relationships/{relationshipTypeTag}/sources` > **[Add direct entity sources for a given entity](/api/rest/entity-relationships/add-direct-entity-sources-for-a-given-entity)** > > `POST /api/v1/catalog/{tagOrId}/relationships/{relationshipTypeTag}/sources` > **[List entity relationships for a relationship type](/api/rest/entity-relationships/list-entity-relationships-for-a-relationship-type)** > > `GET /api/v1/relationships/{relationshipTypeTag}` > **[Update entity relationships for a relationship type](/api/rest/entity-relationships/update-entity-relationships-for-a-relationship-type)** > > `PUT /api/v1/relationships/{relationshipTypeTag}` > **[Add entity relationships for a relationship type](/api/rest/entity-relationships/add-entity-relationships-for-a-relationship-type)** > > `POST /api/v1/relationships/{relationshipTypeTag}` # Add direct entity destinations for a given entity Source: https://docs.cortex.io/api/rest/entity-relationships/add-direct-entity-destinations-for-a-given-entity /openapi/cortex_swagger.json post /api/v1/catalog/{tagOrId}/relationships/{relationshipTypeTag}/destinations Add direct destinations for a given entity and entity relationship type # Add direct entity sources for a given entity Source: https://docs.cortex.io/api/rest/entity-relationships/add-direct-entity-sources-for-a-given-entity /openapi/cortex_swagger.json post /api/v1/catalog/{tagOrId}/relationships/{relationshipTypeTag}/sources Add direct sources for a given entity and entity relationship type # Add entity relationships for a relationship type Source: https://docs.cortex.io/api/rest/entity-relationships/add-entity-relationships-for-a-relationship-type /openapi/cortex_swagger.json post /api/v1/relationships/{relationshipTypeTag} Add all entity relationships for a certain relationship type. # List entity destinations for a relationship type Source: https://docs.cortex.io/api/rest/entity-relationships/list-entity-destinations-for-a-relationship-type /openapi/cortex_swagger.json get /api/v1/catalog/{tagOrId}/relationships/{relationshipTypeTag}/destinations List all entity destinations for a certain relationship type. Optional depth parameter to limit the depth of the relationship tree. # List entity relationships for a relationship type Source: https://docs.cortex.io/api/rest/entity-relationships/list-entity-relationships-for-a-relationship-type /openapi/cortex_swagger.json get /api/v1/relationships/{relationshipTypeTag} List all entity relationships for a certain relationship type. # List entity sources for a relationship type Source: https://docs.cortex.io/api/rest/entity-relationships/list-entity-sources-for-a-relationship-type /openapi/cortex_swagger.json get /api/v1/catalog/{tagOrId}/relationships/{relationshipTypeTag}/sources List all entity sources for a certain relationship type. Optional depth parameter to limit the depth of the relationship tree. # Update direct entity destinations for a given entity Source: https://docs.cortex.io/api/rest/entity-relationships/update-direct-entity-destinations-for-a-given-entity /openapi/cortex_swagger.json put /api/v1/catalog/{tagOrId}/relationships/{relationshipTypeTag}/destinations Update all direct destinations for a given entity and entity relationship type # Update direct entity sources for a given entity Source: https://docs.cortex.io/api/rest/entity-relationships/update-direct-entity-sources-for-a-given-entity /openapi/cortex_swagger.json put /api/v1/catalog/{tagOrId}/relationships/{relationshipTypeTag}/sources Update all direct sources for a given entity and entity relationship type # Update entity relationships for a relationship type Source: https://docs.cortex.io/api/rest/entity-relationships/update-entity-relationships-for-a-relationship-type /openapi/cortex_swagger.json put /api/v1/relationships/{relationshipTypeTag} Update all entity relationships for a certain relationship type. # Entity Types Source: https://docs.cortex.io/api/rest/entity-types Use these operations to interact with [entity types](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/entity-types) in Cortex. ### Required permissions Your API key must have the `Edit entity types` permission. ## Operations > **[List entity types](/api/rest/entity-types/list-entity-types)** > > `GET /api/v1/catalog/definitions` > **[Retrieve entity type](/api/rest/entity-types/retrieve-entity-type)** > > `GET /api/v1/catalog/definitions/{type}` > **[Create entity type](/api/rest/entity-types/create-entity-type)** > > `POST /api/v1/catalog/definitions` > **[Update entity type](/api/rest/entity-types/update-entity-type)** > > `PUT /api/v1/catalog/definitions/{type}` > **[Delete entity type](/api/rest/entity-types/delete-entity-type)** > > `DELETE /api/v1/catalog/definitions/{type}` # Create entity type Source: https://docs.cortex.io/api/rest/entity-types/create-entity-type /openapi/cortex_swagger.json post /api/v1/catalog/definitions # Delete entity type Source: https://docs.cortex.io/api/rest/entity-types/delete-entity-type /openapi/cortex_swagger.json delete /api/v1/catalog/definitions/{type} # List entity types Source: https://docs.cortex.io/api/rest/entity-types/list-entity-types /openapi/cortex_swagger.json get /api/v1/catalog/definitions List entity types Response excludes Cortex default types of service, domain, and team. # Retrieve entity type Source: https://docs.cortex.io/api/rest/entity-types/retrieve-entity-type /openapi/cortex_swagger.json get /api/v1/catalog/definitions/{type} # Update entity type Source: https://docs.cortex.io/api/rest/entity-types/update-entity-type /openapi/cortex_swagger.json put /api/v1/catalog/definitions/{type} # Add a configuration Source: https://docs.cortex.io/api/rest/firehydrant-api/add-a-configuration /openapi/cortex_swagger.json post /api/v1/firehydrant/configuration # Delete a configuration Source: https://docs.cortex.io/api/rest/firehydrant-api/delete-a-configuration /openapi/cortex_swagger.json delete /api/v1/firehydrant/configurations # Retrieve a configuration Source: https://docs.cortex.io/api/rest/firehydrant-api/retrieve-a-configuration /openapi/cortex_swagger.json get /api/v1/firehydrant/default-configuration # Update the existing configuration Source: https://docs.cortex.io/api/rest/firehydrant-api/update-the-existing-configuration /openapi/cortex_swagger.json put /api/v1/firehydrant/configuration # Validate a configuration Source: https://docs.cortex.io/api/rest/firehydrant-api/validate-a-configuration /openapi/cortex_swagger.json post /api/v1/firehydrant/configuration/validate # Add a single app configuration Source: https://docs.cortex.io/api/rest/github-api/add-a-single-app-configuration /openapi/cortex_swagger.json post /api/v1/github/configurations/app # Add a single personal configuration Source: https://docs.cortex.io/api/rest/github-api/add-a-single-personal-configuration /openapi/cortex_swagger.json post /api/v1/github/configurations/personal # Delete a personal configuration Source: https://docs.cortex.io/api/rest/github-api/delete-a-personal-configuration /openapi/cortex_swagger.json delete /api/v1/github/configurations/personal/{alias} # Delete a single app configuration Source: https://docs.cortex.io/api/rest/github-api/delete-a-single-app-configuration /openapi/cortex_swagger.json delete /api/v1/github/configurations/app/{alias} # Delete all configurations Source: https://docs.cortex.io/api/rest/github-api/delete-all-configurations /openapi/cortex_swagger.json delete /api/v1/github/configurations # Retrieve a single app configuration Source: https://docs.cortex.io/api/rest/github-api/retrieve-a-single-app-configuration /openapi/cortex_swagger.json get /api/v1/github/configurations/app/{alias} # Retrieve a single personal configuration Source: https://docs.cortex.io/api/rest/github-api/retrieve-a-single-personal-configuration /openapi/cortex_swagger.json get /api/v1/github/configurations/personal/{alias} # Retrieve configurations Source: https://docs.cortex.io/api/rest/github-api/retrieve-configurations /openapi/cortex_swagger.json get /api/v1/github/configurations # Retrieve default configuration Source: https://docs.cortex.io/api/rest/github-api/retrieve-default-configuration /openapi/cortex_swagger.json get /api/v1/github/default-configuration # Update a single app configuration Source: https://docs.cortex.io/api/rest/github-api/update-a-single-app-configuration /openapi/cortex_swagger.json put /api/v1/github/configurations/app/{alias} # Update a single personal configuration Source: https://docs.cortex.io/api/rest/github-api/update-a-single-personal-configuration /openapi/cortex_swagger.json put /api/v1/github/configurations/personal/{alias} # Validate a configuration Source: https://docs.cortex.io/api/rest/github-api/validate-a-configuration /openapi/cortex_swagger.json post /api/v1/github/configurations/validate/{alias} # Validate all configurations Source: https://docs.cortex.io/api/rest/github-api/validate-all-configurations /openapi/cortex_swagger.json post /api/v1/github/configurations/validate # Add a single configuration Source: https://docs.cortex.io/api/rest/gitlab-api/add-a-single-configuration /openapi/cortex_swagger.json post /api/v1/gitlab/configuration # Add multiple configurations Source: https://docs.cortex.io/api/rest/gitlab-api/add-multiple-configurations /openapi/cortex_swagger.json post /api/v1/gitlab/configurations # Delete a configuration Source: https://docs.cortex.io/api/rest/gitlab-api/delete-a-configuration /openapi/cortex_swagger.json delete /api/v1/gitlab/configuration/{alias} # Delete all configurations Source: https://docs.cortex.io/api/rest/gitlab-api/delete-all-configurations /openapi/cortex_swagger.json delete /api/v1/gitlab/configurations # Retrieve a configuration Source: https://docs.cortex.io/api/rest/gitlab-api/retrieve-a-configuration /openapi/cortex_swagger.json get /api/v1/gitlab/configuration/{alias} # Retrieve configurations Source: https://docs.cortex.io/api/rest/gitlab-api/retrieve-configurations /openapi/cortex_swagger.json get /api/v1/gitlab/configurations # Retrieve default configuration Source: https://docs.cortex.io/api/rest/gitlab-api/retrieve-default-configuration /openapi/cortex_swagger.json get /api/v1/gitlab/default-configuration # Update a configuration Source: https://docs.cortex.io/api/rest/gitlab-api/update-a-configuration /openapi/cortex_swagger.json put /api/v1/gitlab/configuration/{alias} WARNING: Updating aliases for configurations or changing the default configuration could cause entity YAMLs that use this integration to break. # Validate a configuration Source: https://docs.cortex.io/api/rest/gitlab-api/validate-a-configuration /openapi/cortex_swagger.json post /api/v1/gitlab/configuration/validate/{alias} # Validate all configurations Source: https://docs.cortex.io/api/rest/gitlab-api/validate-all-configurations /openapi/cortex_swagger.json post /api/v1/gitlab/configuration/validate # GitOps Logs Source: https://docs.cortex.io/api/rest/gitops-logs Use these operations to interact with [GitOps logs](/configure/gitops/gitops-logs) in Cortex. ### Required permissions Your API key must have the `View GitOps logs` permission. ## Operations > **[Retrieve GitOps logs](/api/rest/gitops-logs/retrieve-gitops-logs)** > > `GET /api/v1/gitops-logs` # Retrieve GitOps logs Source: https://docs.cortex.io/api/rest/gitops-logs/retrieve-gitops-logs /openapi/cortex_swagger.json get /api/v1/gitops-logs API key must have the `View GitOps logs` permission. # Groups Source: https://docs.cortex.io/api/rest/groups Use these operations to interact with [groups](/ingesting-data-into-cortex/entities-overview/entities/groups) on entities in Cortex. ### Required permissions Your API key must have the `Edit entities` permission. ## Operations > **[Retrieve groups for entity](/api/rest/groups/retrieve-groups-for-entity)** > > `GET /api/v1/catalog/{tagOrId}/groups` > **[Add groups to entity](/api/rest/groups/add-groups-to-entity)** > > `PUT /api/v1/catalog/{tagOrId}/groups` > **[Delete groups from entity](/api/rest/groups/delete-groups-from-entity)** > > `DELETE /api/v1/catalog/{tagOrId}/groups` # Add groups to entity Source: https://docs.cortex.io/api/rest/groups/add-groups-to-entity /openapi/cortex_swagger.json put /api/v1/catalog/{tagOrId}/groups # Delete groups from entity Source: https://docs.cortex.io/api/rest/groups/delete-groups-from-entity /openapi/cortex_swagger.json delete /api/v1/catalog/{tagOrId}/groups # Retrieve groups for entity Source: https://docs.cortex.io/api/rest/groups/retrieve-groups-for-entity /openapi/cortex_swagger.json get /api/v1/catalog/{tagOrId}/groups # Add a single configuration Source: https://docs.cortex.io/api/rest/incidentio-api/add-a-single-configuration /openapi/cortex_swagger.json post /api/v1/incidentio/configuration # Add multiple configurations Source: https://docs.cortex.io/api/rest/incidentio-api/add-multiple-configurations /openapi/cortex_swagger.json post /api/v1/incidentio/configurations # Delete a configuration Source: https://docs.cortex.io/api/rest/incidentio-api/delete-a-configuration /openapi/cortex_swagger.json delete /api/v1/incidentio/configuration/{alias} # Delete all configurations Source: https://docs.cortex.io/api/rest/incidentio-api/delete-all-configurations /openapi/cortex_swagger.json delete /api/v1/incidentio/configurations # Retrieve a configuration Source: https://docs.cortex.io/api/rest/incidentio-api/retrieve-a-configuration /openapi/cortex_swagger.json get /api/v1/incidentio/configuration/{alias} # Retrieve configurations Source: https://docs.cortex.io/api/rest/incidentio-api/retrieve-configurations /openapi/cortex_swagger.json get /api/v1/incidentio/configurations # Retrieve default configuration Source: https://docs.cortex.io/api/rest/incidentio-api/retrieve-default-configuration /openapi/cortex_swagger.json get /api/v1/incidentio/default-configuration # Update a configuration Source: https://docs.cortex.io/api/rest/incidentio-api/update-a-configuration /openapi/cortex_swagger.json put /api/v1/incidentio/configuration/{alias} WARNING: Updating aliases for configurations or changing the default configuration could cause entity YAMLs that use this integration to break. # Validate a configuration Source: https://docs.cortex.io/api/rest/incidentio-api/validate-a-configuration /openapi/cortex_swagger.json post /api/v1/incidentio/configuration/validate/{alias} # Validate all configurations Source: https://docs.cortex.io/api/rest/incidentio-api/validate-all-configurations /openapi/cortex_swagger.json post /api/v1/incidentio/configuration/validate # Initiatives Source: https://docs.cortex.io/api/rest/initiatives Use these operations to interact with [Initiatives](/improve/initiatives) in Cortex. ### Required permissions * Create, read, update, or delete Initiatives: Your API key must have the `Edit Initiatives` permission. * View Initiatives: Your API key must have the `View Initiatives` permission. ## Operations > **[List Initiatives](/api/rest/initiatives/list-initiatives)** > > `GET /api/v1/initiatives` > **[Get Initiative](/api/rest/initiatives/get-initiative)** > > `GET /api/v1/initiatives/{cid}` > **[Create an Initiative](/api/rest/initiatives/create-an-initiative)** > > `POST /api/v1/initiatives` > **[Update an Initiative](/api/rest/initiatives/update-an-initiative)** > > `PUT /api/v1/initiatives/{cid}` > **[Delete Initiative](/api/rest/initiatives/delete-initiative)** > > `DELETE /api/v1/initiatives/{cid}` # Create an Initiative Source: https://docs.cortex.io/api/rest/initiatives/create-an-initiative /openapi/cortex_swagger.json post /api/v1/initiatives Create an Initiative. API key must have the `Edit Initiative` permission. # Delete Initiative Source: https://docs.cortex.io/api/rest/initiatives/delete-initiative /openapi/cortex_swagger.json delete /api/v1/initiatives/{cid} # Get Initiative Source: https://docs.cortex.io/api/rest/initiatives/get-initiative /openapi/cortex_swagger.json get /api/v1/initiatives/{cid} Get Initiative. API key must have the `View Initiatives` permission. # List Initiatives Source: https://docs.cortex.io/api/rest/initiatives/list-initiatives /openapi/cortex_swagger.json get /api/v1/initiatives Retrieves a list of Initiatives. API key must have the `View Initiatives` permission. # Update an Initiative Source: https://docs.cortex.io/api/rest/initiatives/update-an-initiative /openapi/cortex_swagger.json put /api/v1/initiatives/{cid} Update an Initiative. API key must have the `Edit Initiative` permission. # Add a configuration Source: https://docs.cortex.io/api/rest/instana-api/add-a-configuration /openapi/cortex_swagger.json post /api/v1/instana/configuration # Delete a configuration Source: https://docs.cortex.io/api/rest/instana-api/delete-a-configuration /openapi/cortex_swagger.json delete /api/v1/instana/configurations # Retrieve a configuration Source: https://docs.cortex.io/api/rest/instana-api/retrieve-a-configuration /openapi/cortex_swagger.json get /api/v1/instana/default-configuration # Update the existing configuration Source: https://docs.cortex.io/api/rest/instana-api/update-the-existing-configuration /openapi/cortex_swagger.json put /api/v1/instana/configuration # Validate a configuration Source: https://docs.cortex.io/api/rest/instana-api/validate-a-configuration /openapi/cortex_swagger.json post /api/v1/instana/configuration/validate # List installed integrations and their status Source: https://docs.cortex.io/api/rest/integration-status/list-installed-integrations-and-their-status /openapi/cortex_swagger.json get /api/v1/integrations/status Returns every installed integration configuration with the result of its most recent connection check. Serves stored results only and never contacts the third-party service. The timestamp is when the connection was last checked, not when data was last synced. # Integrations APIs Source: https://docs.cortex.io/api/rest/integrations # Anthropic API Source: https://docs.cortex.io/api/rest/integrations/anthropic Use these operations to interact with the Anthropic integration in Cortex. ### Required permissions Your API key must have the `Configure Integrations` permission. ## Operations > **[Add a single configuration](/api/rest/anthropic-api/add-a-single-configuration)** > > `POST /api/v1/anthropic/configuration` > **[Validate all configurations](/api/rest/anthropic-api/validate-all-configurations)** > > `POST /api/v1/anthropic/configuration/validate` > **[Validate a configuration](/api/rest/anthropic-api/validate-a-configuration)** > > `POST /api/v1/anthropic/configuration/validate/{alias}` > **[Retrieve a configuration](/api/rest/anthropic-api/retrieve-a-configuration)** > > `GET /api/v1/anthropic/configuration/{alias}` > **[Update a configuration](/api/rest/anthropic-api/update-a-configuration)** > > `PUT /api/v1/anthropic/configuration/{alias}` > **[Delete a configuration](/api/rest/anthropic-api/delete-a-configuration)** > > `DELETE /api/v1/anthropic/configuration/{alias}` > **[Retrieve configurations](/api/rest/anthropic-api/retrieve-configurations)** > > `GET /api/v1/anthropic/configurations` > **[Add multiple configurations](/api/rest/anthropic-api/add-multiple-configurations)** > > `POST /api/v1/anthropic/configurations` > **[Delete all configurations](/api/rest/anthropic-api/delete-all-configurations)** > > `DELETE /api/v1/anthropic/configurations` > **[Retrieve default configuration](/api/rest/anthropic-api/retrieve-default-configuration)** > > `GET /api/v1/anthropic/default-configuration` # Apiiro API Source: https://docs.cortex.io/api/rest/integrations/apiiro Use these operations to interact with the [Apiiro integration](/ingesting-data-into-cortex/integrations/apiiro) in Cortex. ### Required permissions Your API key must have the `Configure integrations` permission. ## Operations > **[Retrieve default configuration](/api/rest/apiiro-api/retrieve-default-configuration)** > > `GET /api/v1/apiiro/default-configuration` > **[Add a single configuration](/api/rest/apiiro-api/add-a-single-configuration)** > > `POST /api/v1/apiiro/configuration` > **[Add multiple configurations](/api/rest/apiiro-api/add-multiple-configurations)** > > `POST /api/v1/apiiro/configurations` > **[Retrieve configurations](/api/rest/apiiro-api/retrieve-configurations)** > > `GET /api/v1/apiiro/configurations` > **[Retrieve a configuration](/api/rest/apiiro-api/retrieve-a-configuration)** > > `GET /api/v1/apiiro/configuration/{alias}` > **[Update a configuration](/api/rest/apiiro-api/update-a-configuration)** > > `PUT /api/v1/apiiro/configuration/{alias}` > **[Delete a configuration](/api/rest/apiiro-api/delete-a-configuration)** > > `DELETE /api/v1/apiiro/configuration/{alias}` > **[Delete all configurations](/api/rest/apiiro-api/delete-all-configurations)** > > `DELETE /api/v1/apiiro/configurations` > **[Validate all configurations](/api/rest/apiiro-api/validate-all-configurations)** > > `POST /api/v1/apiiro/configuration/validate` > **[Validate a configuration](/api/rest/apiiro-api/validate-a-configuration)** > > `POST /api/v1/apiiro/configuration/validate/{alias}` # ArgoCD API Source: https://docs.cortex.io/api/rest/integrations/argocd Use these operations to interact with the [ArgoCD integration](/ingesting-data-into-cortex/integrations/argocd) in Cortex. ### Required permissions Your API key must have the `Configure integrations` permission. ## Operations > **[Retrieve default configuration](/api/rest/argocd-api/retrieve-default-configuration)** > > `GET /api/v1/argocd/default-configuration` > **[Add a single configuration](/api/rest/argocd-api/add-a-single-configuration)** > > `POST /api/v1/argocd/configuration` > **[Add multiple configurations](/api/rest/argocd-api/add-multiple-configurations)** > > `POST /api/v1/argocd/configurations` > **[Retrieve configurations](/api/rest/argocd-api/retrieve-configurations)** > > `GET /api/v1/argocd/configurations` > **[Retrieve a configuration](/api/rest/argocd-api/retrieve-a-configuration)** > > `GET /api/v1/argocd/configuration/{alias}` > **[Update a configuration](/api/rest/argocd-api/update-a-configuration)** > > `PUT /api/v1/argocd/configuration/{alias}` > **[Delete a configuration](/api/rest/argocd-api/delete-a-configuration)** > > `DELETE /api/v1/argocd/configuration/{alias}` > **[Delete all configurations](/api/rest/argocd-api/delete-all-configurations)** > > `DELETE /api/v1/argocd/configurations` > **[Validate all configurations](/api/rest/argocd-api/validate-all-configurations)** > > `POST /api/v1/argocd/configuration/validate` > **[Validate a configuration](/api/rest/argocd-api/validate-a-configuration)** > > `POST /api/v1/argocd/configuration/validate/{alias}` # AWS API Source: https://docs.cortex.io/api/rest/integrations/aws Use these operations to interact with the [AWS integration](/ingesting-data-into-cortex/integrations/aws) in Cortex. ### Required permissions Your API key must have the `Configure integrations` permission. ## Operations > **[List AWS types](/api/rest/aws-api/list-aws-types)** > > `GET /api/v1/aws/types` > **[Retrieve a configuration](/api/rest/aws-api/retrieve-a-configuration)** > > `GET /api/v1/aws/configurations/{accountId}` > **[Retrieve configurations](/api/rest/aws-api/retrieve-configurations)** > > `GET /api/v1/aws/configurations` > **[Add a single configuration](/api/rest/aws-api/add-a-single-configuration)** > > `POST /api/v1/aws/configurations` > **[Validate all configurations](/api/rest/aws-api/validate-all-configurations)** > > `POST /api/v1/aws/configurations/all/validate` > **[Validate a configuration](/api/rest/aws-api/validate-a-configuration)** > > `POST /api/v1/aws/configurations/validate/{accountId}` > **[Update configurations](/api/rest/aws-api/update-configurations)** > > `PUT /api/v1/aws/configurations` > **[Update configured AWS types](/api/rest/aws-api/update-configured-aws-types)** > > `PUT /api/v1/aws/types` > **[Delete all configurations](/api/rest/aws-api/delete-all-configurations)** > > `DELETE /api/v1/aws/configurations` > **[Delete a configuration](/api/rest/aws-api/delete-a-configuration)** > > `DELETE /api/v1/aws/configurations/{accountId}` > **[Get AWS resource details for an entity](/api/rest/aws-api/get-aws-resource-details-for-an-entity)** > > `GET /api/v1/catalog/{tagOrId}/aws` # Azure Active Directory (Entra ID) API Source: https://docs.cortex.io/api/rest/integrations/azure-active-directory Use these operations to interact with the [Azure Active Directory (Entra ID) integration](/ingesting-data-into-cortex/integrations/entraid) in Cortex. ## Operations > **[Retrieve a configuration](/api/rest/azure-active-directory-entra-id-api/retrieve-a-configuration)** > > `GET /api/v1/active-directory/default-configuration` > **[Add a configuration](/api/rest/azure-active-directory-entra-id-api/add-a-configuration)** > > `POST /api/v1/active-directory/configuration` > **[Update the existing configuration](/api/rest/azure-active-directory-entra-id-api/update-the-existing-configuration)** > > `PUT /api/v1/active-directory/configuration` > **[Validate a configuration](/api/rest/azure-active-directory-entra-id-api/validate-a-configuration)** > > `POST /api/v1/active-directory/configuration/validate` > **[Delete a configuration](/api/rest/azure-active-directory-entra-id-api/delete-a-configuration)** > > `DELETE /api/v1/active-directory/configurations` # Azure DevOps API Source: https://docs.cortex.io/api/rest/integrations/azure-devops Use these operations to interact with the [Azure DevOps integration](/ingesting-data-into-cortex/integrations/azuredevops) in Cortex. ### Required permissions Your API key must have the `Configure integrations` permission. ## Operations > **[Retrieve configurations](/api/rest/azure-devops-api/retrieve-configurations)** > > `GET /api/v1/azure-devops/configurations` > **[Retrieve default configuration](/api/rest/azure-devops-api/retrieve-default-configuration)** > > `GET /api/v1/azure-devops/default-configuration` > **[Retrieve a configuration](/api/rest/azure-devops-api/retrieve-a-configuration)** > > `GET /api/v1/azure-devops/configuration/{alias}` > **[Add a single configuration](/api/rest/azure-devops-api/add-a-single-configuration)** > > `POST /api/v1/azure-devops/configuration` > **[Validate all configurations](/api/rest/azure-devops-api/validate-all-configurations)** > > `POST /api/v1/azure-devops/configuration/validate` > **[Add multiple configurations](/api/rest/azure-devops-api/add-multiple-configurations)** > > `POST /api/v1/azure-devops/configurations` > **[Validate a configuration](/api/rest/azure-devops-api/validate-a-configuration)** > > `POST /api/v1/azure-devops/configuration/validate/{alias}` > **[Update a configuration](/api/rest/azure-devops-api/update-a-configuration)** > > `PUT /api/v1/azure-devops/configuration/{alias}` > **[Delete a configuration](/api/rest/azure-devops-api/delete-a-configuration)** > > `DELETE /api/v1/azure-devops/configuration/{alias}` > **[Delete all configurations](/api/rest/azure-devops-api/delete-all-configurations)** > > `DELETE /api/v1/azure-devops/configurations` # Azure Resources API Source: https://docs.cortex.io/api/rest/integrations/azure-resources Use these operations to interact with the [Azure Resources integration](/ingesting-data-into-cortex/integrations/azureresources) in Cortex. ### Required permissions Your API key must have the `Configure integrations` permission. ## Operations > **[List Azure Resources types](/api/rest/azure-resources-api/list-azure-resources-types)** > > `GET /api/v1/azure-resources/types` > **[Retrieve configurations](/api/rest/azure-resources-api/retrieve-configurations)** > > `GET /api/v1/azure-resources/configurations` > **[Retrieve default configuration](/api/rest/azure-resources-api/retrieve-default-configuration)** > > `GET /api/v1/azure-resources/default-configuration` > **[Retrieve a configuration](/api/rest/azure-resources-api/retrieve-a-configuration)** > > `GET /api/v1/azure-resources/configuration/{alias}` > **[Add a single configuration](/api/rest/azure-resources-api/add-a-single-configuration)** > > `POST /api/v1/azure-resources/configuration` > **[Validate all configurations](/api/rest/azure-resources-api/validate-all-configurations)** > > `POST /api/v1/azure-resources/configuration/validate` > **[Validate a configuration](/api/rest/azure-resources-api/validate-a-configuration)** > > `POST /api/v1/azure-resources/configuration/validate/{alias}` > **[Add multiple configurations](/api/rest/azure-resources-api/add-multiple-configurations)** > > `POST /api/v1/azure-resources/configurations` > **[Update configured Azure Resources types](/api/rest/azure-resources-api/update-configured-azure-resources-types)** > > `PUT /api/v1/azure-resources/types` > **[Update a configuration](/api/rest/azure-resources-api/update-a-configuration)** > > `PUT /api/v1/azure-resources/configuration/{alias}` > **[Delete all configurations](/api/rest/azure-resources-api/delete-all-configurations)** > > `DELETE /api/v1/azure-resources/configurations` > **[Delete a configuration](/api/rest/azure-resources-api/delete-a-configuration)** > > `DELETE /api/v1/azure-resources/configuration/{alias}` # BambooHR API Source: https://docs.cortex.io/api/rest/integrations/bamboohr Use these operations to interact with the [BambooHR integration](/ingesting-data-into-cortex/integrations/bamboohr) in Cortex. ### Required permissions Your API key must have the `Configure integrations` permission. ## Operations > **[Retrieve a configuration](/api/rest/bamboohr-api/retrieve-a-configuration)** > > `GET /api/v1/bamboohr/default-configuration` > **[Add a configuration](/api/rest/bamboohr-api/add-a-configuration)** > > `POST /api/v1/bamboohr/configuration` > **[Update the existing configuration](/api/rest/bamboohr-api/update-the-existing-configuration)** > > `PUT /api/v1/bamboohr/configuration` > **[Validate a configuration](/api/rest/bamboohr-api/validate-a-configuration)** > > `POST /api/v1/bamboohr/configuration/validate` > **[Delete a configuration](/api/rest/bamboohr-api/delete-a-configuration)** > > `DELETE /api/v1/bamboohr/configurations` # Bitbucket API Source: https://docs.cortex.io/api/rest/integrations/bitbucket Use these operations to interact with the [Bitbucket integration](/ingesting-data-into-cortex/integrations/bitbucket) in Cortex. ### Required permissions Your API key must have the `Configure integrations` permission. ## Operations > **[Retrieve configurations](/api/rest/bitbucket-api/retrieve-configurations)** > > `GET /api/v1/bitbucket/configurations` > **[Retrieve default configuration](/api/rest/bitbucket-api/retrieve-default-configuration)** > > `GET /api/v1/bitbucket/default-configuration` > **[Retrieve a configuration](/api/rest/bitbucket-api/retrieve-a-configuration)** > > `GET /api/v1/bitbucket/configuration/{alias}` > **[Add multiple configurations](/api/rest/bitbucket-api/add-multiple-configurations)** > > `POST /api/v1/bitbucket/configurations` > **[Add a single configuration](/api/rest/bitbucket-api/add-a-single-configuration)** > > `POST /api/v1/bitbucket/configuration` > **[Validate all configurations](/api/rest/bitbucket-api/validate-all-configurations)** > > `POST /api/v1/bitbucket/configuration/validate` > **[Validate a configuration](/api/rest/bitbucket-api/validate-a-configuration)** > > `POST /api/v1/bitbucket/configuration/validate/{alias}` > **[Update a configuration](/api/rest/bitbucket-api/update-a-configuration)** > > `PUT /api/v1/bitbucket/configuration/{alias}` > **[Delete a configuration](/api/rest/bitbucket-api/delete-a-configuration)** > > `DELETE /api/v1/bitbucket/configuration/{alias}` > **[Delete all configurations](/api/rest/bitbucket-api/delete-all-configurations)** > > `DELETE /api/v1/bitbucket/configurations` # Bugsnag API Source: https://docs.cortex.io/api/rest/integrations/bugsnag Use these operations to interact with the [Bugsnag integration](/ingesting-data-into-cortex/integrations/bugsnag) in Cortex. ### Required permissions Your API key must have the `Configure integrations` permission. ## Operations > **[Retrieve a configuration](/api/rest/bugsnag-api/retrieve-a-configuration)** > > `GET /api/v1/bugsnag/default-configuration` > **[Add a configuration](/api/rest/bugsnag-api/add-a-configuration)** > > `POST /api/v1/bugsnag/configuration` > **[Update the existing configuration](/api/rest/bugsnag-api/update-the-existing-configuration)** > > `PUT /api/v1/bugsnag/configuration` > **[Validate a configuration](/api/rest/bugsnag-api/validate-a-configuration)** > > `POST /api/v1/bugsnag/configuration/validate` > **[Delete a configuration](/api/rest/bugsnag-api/delete-a-configuration)** > > `DELETE /api/v1/bugsnag/configurations` # Buildkite API Source: https://docs.cortex.io/api/rest/integrations/buildkite Use these operations to interact with the [Buildkite integration](/ingesting-data-into-cortex/integrations/buildkite) in Cortex. ### Required permissions Your API key must have the `Configure integrations` permission. ## Operations > **[Retrieve a configuration](/api/rest/buildkite-api/retrieve-a-configuration)** > > `GET /api/v1/buildkite/default-configuration` > **[Add a configuration](/api/rest/buildkite-api/add-a-configuration)** > > `POST /api/v1/buildkite/configuration` > **[Update the existing configuration](/api/rest/buildkite-api/update-the-existing-configuration)** > > `PUT /api/v1/buildkite/configuration` > **[Validate a configuration](/api/rest/buildkite-api/validate-a-configuration)** > > `POST /api/v1/buildkite/configuration/validate` > **[Delete a configuration](/api/rest/buildkite-api/delete-a-configuration)** > > `DELETE /api/v1/buildkite/configurations` # Checkmarx SAST API Source: https://docs.cortex.io/api/rest/integrations/checkmarx-sast Use these operations to interact with the [Checkmarx SAST integration](/api/rest/integrations/checkmarx-sast) in Cortex. ### Required permissions Your API key must have the `Configure integrations` permission. ## Operations > **[Retrieve a configuration](/api/rest/checkmarx-sast-api/retrieve-a-configuration)** > > `GET /api/v1/checkmarx/sast/default-configuration` > **[Add a configuration](/api/rest/checkmarx-sast-api/add-a-configuration)** > > `POST /api/v1/checkmarx/sast/configuration` > **[Update the existing configuration](/api/rest/checkmarx-sast-api/update-the-existing-configuration)** > > `PUT /api/v1/checkmarx/sast/configuration` > **[Validate a configuration](/api/rest/checkmarx-sast-api/validate-a-configuration)** > > `POST /api/v1/checkmarx/sast/configuration/validate` > **[Delete a configuration](/api/rest/checkmarx-sast-api/delete-a-configuration)** > > `DELETE /api/v1/checkmarx/sast/configurations` # CircleCI API Source: https://docs.cortex.io/api/rest/integrations/circleci Use these operations to interact with the [CircleCI integration](/ingesting-data-into-cortex/integrations/circleci) in Cortex. ### Required permissions Your API key must have the `Configure integrations` permission. ## Operations > **[Retrieve configurations](/api/rest/circleci-api/retrieve-configurations)** > > `GET /api/v1/circleci/configurations` > **[Retrieve default configuration](/api/rest/circleci-api/retrieve-default-configuration)** > > `GET /api/v1/circleci/default-configuration` > **[Retrieve a configuration](/api/rest/circleci-api/retrieve-a-configuration)** > > `GET /api/v1/circleci/configuration/{alias}` > **[Add a single configuration](/api/rest/circleci-api/add-a-single-configuration)** > > `POST /api/v1/circleci/configuration` > **[Validate all configurations](/api/rest/circleci-api/validate-all-configurations)** > > `POST /api/v1/circleci/configuration/validate` > **[Add multiple configurations](/api/rest/circleci-api/add-multiple-configurations)** > > `POST /api/v1/circleci/configurations` > **[Validate a configuration](/api/rest/circleci-api/validate-a-configuration)** > > `POST /api/v1/circleci/configuration/validate/{alias}` > **[Update a configuration](/api/rest/circleci-api/update-a-configuration)** > > `PUT /api/v1/circleci/configuration/{alias}` > **[Delete all configurations](/api/rest/circleci-api/delete-all-configurations)** > > `DELETE /api/v1/circleci/configurations` > **[Delete a configuration](/api/rest/circleci-api/delete-a-configuration)** > > `DELETE /api/v1/circleci/configuration/{alias}` # ClickUp API Source: https://docs.cortex.io/api/rest/integrations/clickup Use these operations to interact with the [ClickUp integration](/ingesting-data-into-cortex/integrations/clickup) in Cortex. ### Required permissions Your API key must have the `Configure integrations` permission. ## Operations > **[Retrieve a configuration](/api/rest/clickup-api/retrieve-a-configuration)** > > `GET /api/v1/clickup/default-configuration` > **[Add a configuration](/api/rest/clickup-api/add-a-configuration)** > > `POST /api/v1/clickup/configuration` > **[Update the existing configuration](/api/rest/clickup-api/update-the-existing-configuration)** > > `PUT /api/v1/clickup/configuration` > **[Validate a configuration](/api/rest/clickup-api/validate-a-configuration)** > > `POST /api/v1/clickup/configuration/validate` > **[Delete a configuration](/api/rest/clickup-api/delete-a-configuration)** > > `DELETE /api/v1/clickup/configurations` # Codecov API Source: https://docs.cortex.io/api/rest/integrations/codecov Use these operations to interact with the [Codecov integration](/ingesting-data-into-cortex/integrations/codecov) in Cortex. ### Required permissions Your API key must have the `Configure integrations` permission. ## Operations > **[Retrieve a configuration](/api/rest/codecov-api/retrieve-a-configuration)** > > `GET /api/v1/codecov/default-configuration` > **[Add a configuration](/api/rest/codecov-api/add-a-configuration)** > > `POST /api/v1/codecov/configuration` > **[Update the existing configuration](/api/rest/codecov-api/update-the-existing-configuration)** > > `PUT /api/v1/codecov/configuration` > **[Validate a configuration](/api/rest/codecov-api/validate-a-configuration)** > > `POST /api/v1/codecov/configuration/validate` > **[Delete a configuration](/api/rest/codecov-api/delete-a-configuration)** > > `DELETE /api/v1/codecov/configurations` # Coralogix API Source: https://docs.cortex.io/api/rest/integrations/coralogix Use these operations to interact with the [Coralogix integration](/ingesting-data-into-cortex/integrations/coralogix) in Cortex. ### Required permissions Your API key must have the `Configure integrations` permission. ## Operations > **[Retrieve configurations](/api/rest/coralogix-api/retrieve-configurations)** > > `GET /api/v1/coralogix/configurations` > **[Retrieve default configuration](/api/rest/coralogix-api/retrieve-default-configuration)** > > `GET /api/v1/coralogix/default-configuration` > **[Retrieve a configuration](/api/rest/coralogix-api/retrieve-a-configuration)** > > `GET /api/v1/coralogix/configuration/{alias}` > **[Validate all configurations](/api/rest/coralogix-api/validate-all-configurations)** > > `POST /api/v1/coralogix/configuration/validate` > **[Add multiple configurations](/api/rest/coralogix-api/add-multiple-configurations)** > > `POST /api/v1/coralogix/configurations` > **[Add a single configuration](/api/rest/coralogix-api/add-a-single-configuration)** > > `POST /api/v1/coralogix/configuration` > **[Validate a configuration](/api/rest/coralogix-api/validate-a-configuration)** > > `POST /api/v1/coralogix/configuration/validate/{alias}` > **[Update a configuration](/api/rest/coralogix-api/update-a-configuration)** > > `PUT /api/v1/coralogix/configuration/{alias}` > **[Delete all configurations](/api/rest/coralogix-api/delete-all-configurations)** > > `DELETE /api/v1/coralogix/configurations` > **[Delete a configuration](/api/rest/coralogix-api/delete-a-configuration)** > > `DELETE /api/v1/coralogix/configuration/{alias}` # Datadog API Source: https://docs.cortex.io/api/rest/integrations/datadog Use these operations to interact with the [Datadog integration](/ingesting-data-into-cortex/integrations/datadog) in Cortex. ### Required permissions Your API key must have the `Configure integrations` permission. ## Operations > **[Retrieve configurations](/api/rest/datadog-api/retrieve-configurations)** > > `GET /api/v1/datadog/configurations` > **[Retrieve default configuration](/api/rest/datadog-api/retrieve-default-configuration)** > > `GET /api/v1/datadog/default-configuration` > **[Retrieve a configuration](/api/rest/datadog-api/retrieve-a-configuration)** > > `GET /api/v1/datadog/configuration/{alias}` > **[Add multiple configurations](/api/rest/datadog-api/add-multiple-configurations)** > > `POST /api/v1/datadog/configurations` > **[Add a single configuration](/api/rest/datadog-api/add-a-single-configuration)** > > `POST /api/v1/datadog/configuration` > **[Validate all configurations](/api/rest/datadog-api/validate-all-configurations)** > > `POST /api/v1/datadog/configuration/validate` > **[Validate a configuration](/api/rest/datadog-api/validate-a-configuration)** > > `POST /api/v1/datadog/configuration/validate/{alias}` > **[Update a configuration](/api/rest/datadog-api/update-a-configuration)** > > `PUT /api/v1/datadog/configuration/{alias}` > **[Delete a configuration](/api/rest/datadog-api/delete-a-configuration)** > > `DELETE /api/v1/datadog/configuration/{alias}` > **[Delete all configurations](/api/rest/datadog-api/delete-all-configurations)** > > `DELETE /api/v1/datadog/configurations` # Dynatrace API Source: https://docs.cortex.io/api/rest/integrations/dynatrace Use these operations to interact with the [Dynatrace integration](/ingesting-data-into-cortex/integrations/dynatrace) in Cortex. ### Required permissions Your API key must have the `Configure integrations` permission. ## Operations > **[Retrieve a configuration](/api/rest/dynatrace-api/retrieve-a-configuration)** > > `GET /api/v1/dynatrace/default-configuration` > **[Add a configuration](/api/rest/dynatrace-api/add-a-configuration)** > > `POST /api/v1/dynatrace/configuration` > **[Update the existing configuration](/api/rest/dynatrace-api/update-the-existing-configuration)** > > `PUT /api/v1/dynatrace/configuration` > **[Validate a configuration](/api/rest/dynatrace-api/validate-a-configuration)** > > `POST /api/v1/dynatrace/configuration/validate` > **[Delete a configuration](/api/rest/dynatrace-api/delete-a-configuration)** > > `DELETE /api/v1/dynatrace/configurations` # Firehydrant API Source: https://docs.cortex.io/api/rest/integrations/firehydrant Use these operations to interact with the [Firehydrant integration](/ingesting-data-into-cortex/integrations/firehydrant) in Cortex. ### Required permissions Your API key must have the `Configure integrations` permission. ## Operations > **[Retrieve a configuration](/api/rest/firehydrant-api/retrieve-a-configuration)** > > `GET /api/v1/firehydrant/default-configuration` > **[Add a configuration](/api/rest/firehydrant-api/add-a-configuration)** > > `POST /api/v1/firehydrant/configuration` > **[Update the existing configuration](/api/rest/firehydrant-api/update-the-existing-configuration)** > > `PUT /api/v1/firehydrant/configuration` > **[Validate a configuration](/api/rest/firehydrant-api/validate-a-configuration)** > > `POST /api/v1/firehydrant/configuration/validate` > **[Delete a configuration](/api/rest/firehydrant-api/delete-a-configuration)** > > `DELETE /api/v1/firehydrant/configurations` # GitHub API Source: https://docs.cortex.io/api/rest/integrations/github Use these operations to interact with the [GitHub integration](/ingesting-data-into-cortex/integrations/github) in Cortex. ### Required permissions Your API key must have the `Configure integrations` permission. ## Operations > **[Retrieve configurations](/api/rest/github-api/retrieve-configurations)** > > `GET /api/v1/github/configurations` > **[Retrieve default configuration](/api/rest/github-api/retrieve-default-configuration)** > > `GET /api/v1/github/default-configuration` > **[Retrieve a single personal configuration](/api/rest/github-api/retrieve-a-single-personal-configuration)** > > `GET /api/v1/github/configurations/personal/{alias}` > **[Retrieve a single app configuration](/api/rest/github-api/retrieve-a-single-app-configuration)** > > `GET /api/v1/github/configurations/app/{alias}` > **[Validate all configurations](/api/rest/github-api/validate-all-configurations)** > > `POST /api/v1/github/configurations/validate` > **[Add a single app configuration](/api/rest/github-api/add-a-single-app-configuration)** > > `POST /api/v1/github/configurations/app` > **[Validate a configuration](/api/rest/github-api/validate-a-configuration)** > > `POST /api/v1/github/configurations/validate/{alias}` > **[Add a single personal configuration](/api/rest/github-api/add-a-single-personal-configuration)** > > `POST /api/v1/github/configurations/personal` > **[Update a single app configuration](/api/rest/github-api/update-a-single-app-configuration)** > > `PUT /api/v1/github/configurations/app/{alias}` > **[Delete a personal configuration](/api/rest/github-api/delete-a-personal-configuration)** > > `DELETE /api/v1/github/configurations/personal/{alias}` > **[Update a single personal configuration](/api/rest/github-api/update-a-single-personal-configuration)** > > `PUT /api/v1/github/configurations/personal/{alias}` > **[Delete all configurations](/api/rest/github-api/delete-all-configurations)** > > `DELETE /api/v1/github/configurations` > **[Delete a single app configuration](/api/rest/github-api/delete-a-single-app-configuration)** > > `DELETE /api/v1/github/configurations/app/{alias}` # GitLab API Source: https://docs.cortex.io/api/rest/integrations/gitlab Use these operations to interact with the [GitLab integration](/ingesting-data-into-cortex/integrations/gitlab) in Cortex. ### Required permissions Your API key must have the `Configure integrations` permission. ## Operations > **[Retrieve configurations](/api/rest/gitlab-api/retrieve-configurations)** > > `GET /api/v1/gitlab/configurations` > **[Retrieve default configuration](/api/rest/gitlab-api/retrieve-default-configuration)** > > `GET /api/v1/gitlab/default-configuration` > **[Retrieve a configuration](/api/rest/gitlab-api/retrieve-a-configuration)** > > `GET /api/v1/gitlab/configuration/{alias}` > **[Add a single configuration](/api/rest/gitlab-api/add-a-single-configuration)** > > `POST /api/v1/gitlab/configuration` > **[Validate all configurations](/api/rest/gitlab-api/validate-all-configurations)** > > `POST /api/v1/gitlab/configuration/validate` > **[Validate a configuration](/api/rest/gitlab-api/validate-a-configuration)** > > `POST /api/v1/gitlab/configuration/validate/{alias}` > **[Update a configuration](/api/rest/gitlab-api/update-a-configuration)** > > `PUT /api/v1/gitlab/configuration/{alias}` > **[Add multiple configurations](/api/rest/gitlab-api/add-multiple-configurations)** > > `POST /api/v1/gitlab/configurations` > **[Delete all configurations](/api/rest/gitlab-api/delete-all-configurations)** > > `DELETE /api/v1/gitlab/configurations` > **[Delete a configuration](/api/rest/gitlab-api/delete-a-configuration)** > > `DELETE /api/v1/gitlab/configuration/{alias}` # incident.io API Source: https://docs.cortex.io/api/rest/integrations/incidentio Use these operations to interact with the [incident.io integration](/ingesting-data-into-cortex/integrations/incidentio) in Cortex. ### Required permissions Your API key must have the `Configure integrations` permission. ## Operations > **[Retrieve configurations](/api/rest/incidentio-api/retrieve-configurations)** > > `GET /api/v1/incidentio/configurations` > **[Retrieve default configuration](/api/rest/incidentio-api/retrieve-default-configuration)** > > `GET /api/v1/incidentio/default-configuration` > **[Retrieve a configuration](/api/rest/incidentio-api/retrieve-a-configuration)** > > `GET /api/v1/incidentio/configuration/{alias}` > **[Add multiple configurations](/api/rest/incidentio-api/add-multiple-configurations)** > > `POST /api/v1/incidentio/configurations` > **[Add a single configuration](/api/rest/incidentio-api/add-a-single-configuration)** > > `POST /api/v1/incidentio/configuration` > **[Validate all configurations](/api/rest/incidentio-api/validate-all-configurations)** > > `POST /api/v1/incidentio/configuration/validate` > **[Validate a configuration](/api/rest/incidentio-api/validate-a-configuration)** > > `POST /api/v1/incidentio/configuration/validate/{alias}` > **[Update a configuration](/api/rest/incidentio-api/update-a-configuration)** > > `PUT /api/v1/incidentio/configuration/{alias}` > **[Delete all configurations](/api/rest/incidentio-api/delete-all-configurations)** > > `DELETE /api/v1/incidentio/configurations` > **[Delete a configuration](/api/rest/incidentio-api/delete-a-configuration)** > > `DELETE /api/v1/incidentio/configuration/{alias}` # Instana API Source: https://docs.cortex.io/api/rest/integrations/instana Use these operations to interact with the [Instana integration](/ingesting-data-into-cortex/integrations/instana) in Cortex. ### Required permissions Your API key must have the `Configure integrations` permission. ## Operations > **[Retrieve a configuration](/api/rest/instana-api/retrieve-a-configuration)** > > `GET /api/v1/instana/default-configuration` > **[Add a configuration](/api/rest/instana-api/add-a-configuration)** > > `POST /api/v1/instana/configuration` > **[Update the existing configuration](/api/rest/instana-api/update-the-existing-configuration)** > > `PUT /api/v1/instana/configuration` > **[Validate a configuration](/api/rest/instana-api/validate-a-configuration)** > > `POST /api/v1/instana/configuration/validate` > **[Delete a configuration](/api/rest/instana-api/delete-a-configuration)** > > `DELETE /api/v1/instana/configurations` # Jenkins API Source: https://docs.cortex.io/api/rest/integrations/jenkins Use these operations to interact with the [Jenkins integration](/ingesting-data-into-cortex/integrations/jenkins) in Cortex. ### Required permissions Your API key must have the `Configure integrations` permission. ## Operations > **[Retrieve default configuration](/api/rest/jenkins-api/retrieve-default-configuration)** > > `GET /api/v1/jenkins/default-configuration` > **[Add a single configuration](/api/rest/jenkins-api/add-a-single-configuration)** > > `POST /api/v1/jenkins/configuration` > **[Add multiple configurations](/api/rest/jenkins-api/add-multiple-configurations)** > > `POST /api/v1/jenkins/configurations` > **[Retrieve configurations](/api/rest/jenkins-api/retrieve-configurations)** > > `GET /api/v1/jenkins/configurations` > **[Retrieve a configuration](/api/rest/jenkins-api/retrieve-a-configuration)** > > `GET /api/v1/jenkins/configuration/{alias}` > **[Update a configuration](/api/rest/jenkins-api/update-a-configuration)** > > `PUT /api/v1/jenkins/configuration/{alias}` > **[Delete a configuration](/api/rest/jenkins-api/delete-a-configuration)** > > `DELETE /api/v1/jenkins/configuration/{alias}` > **[Delete all configurations](/api/rest/jenkins-api/delete-all-configurations)** > > `DELETE /api/v1/jenkins/configurations` > **[Validate all configurations](/api/rest/jenkins-api/validate-all-configurations)** > > `POST /api/v1/jenkins/configuration/validate` > **[Validate a configuration](/api/rest/jenkins-api/validate-a-configuration)** > > `POST /api/v1/jenkins/configuration/validate/{alias}` # Jira API Source: https://docs.cortex.io/api/rest/integrations/jira Use these operations to interact with the [Jira integration](/ingesting-data-into-cortex/integrations/jira) in Cortex. ### Required permissions Your API key must have the `Configure integrations` permission. ## Operations > **[Retrieve configurations](/api/rest/jira-api/retrieve-configurations)** > > `GET /api/v1/jira/configurations` > **[Retrieve default configuration](/api/rest/jira-api/retrieve-default-configuration)** > > `GET /api/v1/jira/default-configuration` > **[Retrieve a configuration](/api/rest/jira-api/retrieve-a-configuration)** > > `GET /api/v1/jira/configuration/{alias}` > **[Add multiple configurations](/api/rest/jira-api/add-multiple-configurations)** > > `POST /api/v1/jira/configurations` > **[Add a single configuration](/api/rest/jira-api/add-a-single-configuration)** > > `POST /api/v1/jira/configuration` > **[Validate all configurations](/api/rest/jira-api/validate-all-configurations)** > > `POST /api/v1/jira/configuration/validate` > **[Validate a configuration](/api/rest/jira-api/validate-a-configuration)** > > `POST /api/v1/jira/configuration/validate/{alias}` > **[Update a configuration](/api/rest/jira-api/update-a-configuration)** > > `PUT /api/v1/jira/configuration/{alias}` > **[Delete a configuration](/api/rest/jira-api/delete-a-configuration)** > > `DELETE /api/v1/jira/configuration/{alias}` > **[Delete all configurations](/api/rest/jira-api/delete-all-configurations)** > > `DELETE /api/v1/jira/configurations` # LaunchDarkly API Source: https://docs.cortex.io/api/rest/integrations/launchdarkly Use these operations to interact with the [LaunchDarkly integration](/ingesting-data-into-cortex/integrations/launchdarkly) in Cortex. ### Required permissions Your API key must have the `Configure integrations` permission. ## Operations > **[Retrieve configurations](/api/rest/launchdarkly-api/retrieve-configurations)** > > `GET /api/v1/launchdarkly/configurations` > **[Retrieve default configuration](/api/rest/launchdarkly-api/retrieve-default-configuration)** > > `GET /api/v1/launchdarkly/default-configuration` > **[Retrieve a configuration](/api/rest/launchdarkly-api/retrieve-a-configuration)** > > `GET /api/v1/launchdarkly/configuration/{alias}` > **[Add multiple configurations](/api/rest/launchdarkly-api/add-multiple-configurations)** > > `POST /api/v1/launchdarkly/configurations` > **[Add a single configuration](/api/rest/launchdarkly-api/add-a-single-configuration)** > > `POST /api/v1/launchdarkly/configuration` > **[Validate all configurations](/api/rest/launchdarkly-api/validate-all-configurations)** > > `POST /api/v1/launchdarkly/configuration/validate` > **[Validate a configuration](/api/rest/launchdarkly-api/validate-a-configuration)** > > `POST /api/v1/launchdarkly/configuration/validate/{alias}` > **[Update a configuration](/api/rest/launchdarkly-api/update-a-configuration)** > > `PUT /api/v1/launchdarkly/configuration/{alias}` > **[Delete a configuration](/api/rest/launchdarkly-api/delete-a-configuration)** > > `DELETE /api/v1/launchdarkly/configuration/{alias}` > **[Delete all configurations](/api/rest/launchdarkly-api/delete-all-configurations)** > > `DELETE /api/v1/launchdarkly/configurations` # Mend API Source: https://docs.cortex.io/api/rest/integrations/mend Use these operations to interact with the [Mend integration](/ingesting-data-into-cortex/integrations/mend) in Cortex. Mend provides two separate products — SAST and SCA — each configured independently. ### Required permissions Your API key must have the `Configure integrations` permission. ## Mend SAST operations > **[Retrieve a configuration](/api/rest/mend-sast-api/retrieve-a-configuration)** > > `GET /api/v1/mend/sast/default-configuration` > **[Add a configuration](/api/rest/mend-sast-api/add-a-configuration)** > > `POST /api/v1/mend/sast/configuration` > **[Update the existing configuration](/api/rest/mend-sast-api/update-the-existing-configuration)** > > `PUT /api/v1/mend/sast/configuration` > **[Validate a configuration](/api/rest/mend-sast-api/validate-a-configuration)** > > `POST /api/v1/mend/sast/configuration/validate` > **[Delete a configuration](/api/rest/mend-sast-api/delete-a-configuration)** > > `DELETE /api/v1/mend/sast/configurations` ## Mend SCA operations > **[Retrieve a configuration](/api/rest/mend-sca-api/retrieve-a-configuration)** > > `GET /api/v1/mend/sca/default-configuration` > **[Add a configuration](/api/rest/mend-sca-api/add-a-configuration)** > > `POST /api/v1/mend/sca/configuration` > **[Update the existing configuration](/api/rest/mend-sca-api/update-the-existing-configuration)** > > `PUT /api/v1/mend/sca/configuration` > **[Validate a configuration](/api/rest/mend-sca-api/validate-a-configuration)** > > `POST /api/v1/mend/sca/configuration/validate` > **[Delete a configuration](/api/rest/mend-sca-api/delete-a-configuration)** > > `DELETE /api/v1/mend/sca/configurations` # New Relic API Source: https://docs.cortex.io/api/rest/integrations/new-relic Use these operations to interact with the [New Relic integration](/ingesting-data-into-cortex/integrations/newrelic) in Cortex. ### Required permissions Your API key must have the `Configure integrations` permission. ## Operations > **[Retrieve configurations](/api/rest/new-relic-api/retrieve-configurations)** > > `GET /api/v1/newrelic/configurations` > **[Retrieve default configuration](/api/rest/new-relic-api/retrieve-default-configuration)** > > `GET /api/v1/newrelic/default-configuration` > **[Retrieve a configuration](/api/rest/new-relic-api/retrieve-a-configuration)** > > `GET /api/v1/newrelic/configuration/{alias}` > **[Add multiple configurations](/api/rest/new-relic-api/add-multiple-configurations)** > > `POST /api/v1/newrelic/configurations` > **[Add a single configuration](/api/rest/new-relic-api/add-a-single-configuration)** > > `POST /api/v1/newrelic/configuration` > **[Validate all configurations](/api/rest/new-relic-api/validate-all-configurations)** > > `POST /api/v1/newrelic/configuration/validate` > **[Validate a configuration](/api/rest/new-relic-api/validate-a-configuration)** > > `POST /api/v1/newrelic/configuration/validate/{alias}` > **[Update a configuration](/api/rest/new-relic-api/update-a-configuration)** > > `PUT /api/v1/newrelic/configuration/{alias}` > **[Delete all configurations](/api/rest/new-relic-api/delete-all-configurations)** > > `DELETE /api/v1/newrelic/configurations` > **[Delete a configuration](/api/rest/new-relic-api/delete-a-configuration)** > > `DELETE /api/v1/newrelic/configuration/{alias}` # Okta API Source: https://docs.cortex.io/api/rest/integrations/okta Use these operations to interact with the [Okta integration](/ingesting-data-into-cortex/integrations/okta) in Cortex. ### Required permissions Your API key must have the `Configure integrations` permission. ## Operations > **[Retrieve a configuration](/api/rest/okta-api/retrieve-a-configuration)** > > `GET /api/v1/okta/default-configuration` > **[Add a configuration](/api/rest/okta-api/add-a-configuration)** > > `POST /api/v1/okta/configuration` > **[Update the existing configuration](/api/rest/okta-api/update-the-existing-configuration)** > > `PUT /api/v1/okta/configuration` > **[Validate a configuration](/api/rest/okta-api/validate-a-configuration)** > > `POST /api/v1/okta/configuration/validate` > **[Delete a configuration](/api/rest/okta-api/delete-a-configuration)** > > `DELETE /api/v1/okta/configurations` # Opsgenie API Source: https://docs.cortex.io/api/rest/integrations/opsgenie Use these operations to interact with the [Opsgenie integration](/ingesting-data-into-cortex/integrations/opsgenie) in Cortex. ### Required permissions Your API key must have the `Configure integrations` permission. ## Operations > **[Retrieve a configuration](/api/rest/opsgenie-api/retrieve-a-configuration)** > > `GET /api/v1/opsgenie/default-configuration` > **[Add a configuration](/api/rest/opsgenie-api/add-a-configuration)** > > `POST /api/v1/opsgenie/configuration` > **[Update the existing configuration](/api/rest/opsgenie-api/update-the-existing-configuration)** > > `PUT /api/v1/opsgenie/configuration` > **[Validate a configuration](/api/rest/opsgenie-api/validate-a-configuration)** > > `POST /api/v1/opsgenie/configuration/validate` > **[Delete a configuration](/api/rest/opsgenie-api/delete-a-configuration)** > > `DELETE /api/v1/opsgenie/configurations` # PagerDuty API Source: https://docs.cortex.io/api/rest/integrations/pagerduty Use these operations to interact with the [PagerDuty integration](/ingesting-data-into-cortex/integrations/pagerduty) in Cortex. ### Required permissions Your API key must have the `Configure integrations` permission. ## Operations > **[Retrieve a configuration](/api/rest/pagerduty-api/retrieve-a-configuration)** > > `GET /api/v1/pagerduty/default-configuration` > **[Add a configuration](/api/rest/pagerduty-api/add-a-configuration)** > > `POST /api/v1/pagerduty/configuration` > **[Update the existing configuration](/api/rest/pagerduty-api/update-the-existing-configuration)** > > `PUT /api/v1/pagerduty/configuration` > **[Validate a configuration](/api/rest/pagerduty-api/validate-a-configuration)** > > `POST /api/v1/pagerduty/configuration/validate` > **[Delete a configuration](/api/rest/pagerduty-api/delete-a-configuration)** > > `DELETE /api/v1/pagerduty/configurations` # Prometheus API Source: https://docs.cortex.io/api/rest/integrations/prometheus Use these operations to interact with the [Prometheus integration](/ingesting-data-into-cortex/integrations/prometheus) in Cortex. ### Required permissions Your API key must have the `Configure integrations` permission. ## Operations > **[Retrieve configurations](/api/rest/prometheus-api/retrieve-configurations)** > > `GET /api/v1/prometheus/configurations` > **[Retrieve default configuration](/api/rest/prometheus-api/retrieve-default-configuration)** > > `GET /api/v1/prometheus/default-configuration` > **[Retrieve a configuration](/api/rest/prometheus-api/retrieve-a-configuration)** > > `GET /api/v1/prometheus/configuration/{alias}` > **[Add multiple configurations](/api/rest/prometheus-api/add-multiple-configurations)** > > `POST /api/v1/prometheus/configurations` > **[Add a single configuration](/api/rest/prometheus-api/add-a-single-configuration)** > > `POST /api/v1/prometheus/configuration` > **[Validate all configurations](/api/rest/prometheus-api/validate-all-configurations)** > > `POST /api/v1/prometheus/configuration/validate` > **[Validate a configuration](/api/rest/prometheus-api/validate-a-configuration)** > > `POST /api/v1/prometheus/configuration/validate/{alias}` > **[Update a configuration](/api/rest/prometheus-api/update-a-configuration)** > > `PUT /api/v1/prometheus/configuration/{alias}` > **[Delete a configuration](/api/rest/prometheus-api/delete-a-configuration)** > > `DELETE /api/v1/prometheus/configuration/{alias}` > **[Delete all configurations](/api/rest/prometheus-api/delete-all-configurations)** > > `DELETE /api/v1/prometheus/configurations` # Rollbar API Source: https://docs.cortex.io/api/rest/integrations/rollbar Use these operations to interact with the [Rollbar integration](/ingesting-data-into-cortex/integrations/rollbar) in Cortex. ### Required permissions Your API key must have the `Configure integrations` permission. ## Operations > **[Retrieve a configuration](/api/rest/rollbar-api/retrieve-a-configuration)** > > `GET /api/v1/rollbar/default-configuration` > **[Add a configuration](/api/rest/rollbar-api/add-a-configuration)** > > `POST /api/v1/rollbar/configuration` > **[Update the existing configuration](/api/rest/rollbar-api/update-the-existing-configuration)** > > `PUT /api/v1/rollbar/configuration` > **[Validate a configuration](/api/rest/rollbar-api/validate-a-configuration)** > > `POST /api/v1/rollbar/configuration/validate` > **[Delete a configuration](/api/rest/rollbar-api/delete-a-configuration)** > > `DELETE /api/v1/rollbar/configurations` # Rootly API Source: https://docs.cortex.io/api/rest/integrations/rootly Use these operations to interact with the [Rootly integration](/ingesting-data-into-cortex/integrations/rootly) in Cortex. ### Required permissions Your API key must have the `Configure integrations` permission. ## Operations > **[Retrieve default configuration](/api/rest/rootly-api/retrieve-default-configuration)** > > `GET /api/v1/rootly/default-configuration` > **[Add a configuration](/api/rest/rootly-api/add-a-configuration)** > > `POST /api/v1/rootly/configuration` > **[Retrieve all configurations](/api/rest/rootly-api/retrieve-all-configurations)** > > `GET /api/v1/rootly/configurations` > **[Retrieve a configuration by alias](/api/rest/rootly-api/retrieve-a-configuration-by-alias)** > > `GET /api/v1/rootly/configuration/{alias}` > **[Update a configuration](/api/rest/rootly-api/update-a-configuration)** > > `PUT /api/v1/rootly/configuration/{alias}` > **[Delete a configuration by alias](/api/rest/rootly-api/delete-a-configuration-by-alias)** > > `DELETE /api/v1/rootly/configuration/{alias}` # Semgrep API Source: https://docs.cortex.io/api/rest/integrations/semgrep Use these operations to interact with the [Semgrep integration](/ingesting-data-into-cortex/integrations/semgrep) in Cortex. ### Required permissions Your API key must have the `Configure integrations` permission. ## Operations > **[Retrieve configurations](/api/rest/semgrep-api/retrieve-configurations)** > > `GET /api/v1/semgrep/configurations` > **[Retrieve default configuration](/api/rest/semgrep-api/retrieve-default-configuration)** > > `GET /api/v1/semgrep/default-configuration` > **[Retrieve a configuration](/api/rest/semgrep-api/retrieve-a-configuration)** > > `GET /api/v1/semgrep/configuration/{alias}` > **[Add multiple configurations](/api/rest/semgrep-api/add-multiple-configurations)** > > `POST /api/v1/semgrep/configurations` > **[Add a single configuration](/api/rest/semgrep-api/add-a-single-configuration)** > > `POST /api/v1/semgrep/configuration` > **[Validate all configurations](/api/rest/semgrep-api/validate-all-configurations)** > > `POST /api/v1/semgrep/configuration/validate` > **[Validate a configuration](/api/rest/semgrep-api/validate-a-configuration)** > > `POST /api/v1/semgrep/configuration/validate/{alias}` > **[Update a configuration](/api/rest/semgrep-api/update-a-configuration)** > > `PUT /api/v1/semgrep/configuration/{alias}` > **[Delete a configuration](/api/rest/semgrep-api/delete-a-configuration)** > > `DELETE /api/v1/semgrep/configuration/{alias}` > **[Delete all configurations](/api/rest/semgrep-api/delete-all-configurations)** > > `DELETE /api/v1/semgrep/configurations` # Sentry API Source: https://docs.cortex.io/api/rest/integrations/sentry Use these operations to interact with the [Sentry integration](/ingesting-data-into-cortex/integrations/sentry) in Cortex. ### Required permissions Your API key must have the `Configure integrations` permission. ## Operations > **[Retrieve a configuration](/api/rest/sentry-api/retrieve-a-configuration)** > > `GET /api/v1/sentry/default-configuration` > **[Add a configuration](/api/rest/sentry-api/add-a-configuration)** > > `POST /api/v1/sentry/configuration` > **[Update the existing configuration](/api/rest/sentry-api/update-the-existing-configuration)** > > `PUT /api/v1/sentry/configuration` > **[Validate a configuration](/api/rest/sentry-api/validate-a-configuration)** > > `POST /api/v1/sentry/configuration/validate` > **[Delete a configuration](/api/rest/sentry-api/delete-a-configuration)** > > `DELETE /api/v1/sentry/configurations` # ServiceNow API Source: https://docs.cortex.io/api/rest/integrations/servicenow Use these operations to interact with the [ServiceNow integration](/ingesting-data-into-cortex/integrations/servicenow) in Cortex. ### Required permissions Your API key must have the `Configure integrations` permission. ## Operations > **[Retrieve a configuration](/api/rest/servicenow-api/retrieve-a-configuration)** > > `GET /api/v1/servicenow/default-configuration` > **[Add a configuration](/api/rest/servicenow-api/add-a-configuration)** > > `POST /api/v1/servicenow/configuration` > **[Update the existing configuration](/api/rest/servicenow-api/update-the-existing-configuration)** > > `PUT /api/v1/servicenow/configuration` > **[Validate a configuration](/api/rest/servicenow-api/validate-a-configuration)** > > `POST /api/v1/servicenow/configuration/validate` > **[Delete a configuration](/api/rest/servicenow-api/delete-a-configuration)** > > `DELETE /api/v1/servicenow/configurations` # ServiceNow Cloud Observability API Source: https://docs.cortex.io/api/rest/integrations/servicenow-cloud-observability Use these operations to interact with the [ServiceNow Cloud Observability integration](/api/rest/integrations/servicenow-cloud-observability) in Cortex. ### Required permissions Your API key must have the `Configure integrations` permission. ## Operations > **[Retrieve a configuration](/api/rest/servicenow-cloud-observability-api/retrieve-a-configuration)** > > `GET /api/v1/lightstep/default-configuration` > **[Add a configuration](/api/rest/servicenow-cloud-observability-api/add-a-configuration)** > > `POST /api/v1/lightstep/configuration` > **[Update the existing configuration](/api/rest/servicenow-cloud-observability-api/update-the-existing-configuration)** > > `PUT /api/v1/lightstep/configuration` > **[Validate a configuration](/api/rest/servicenow-cloud-observability-api/validate-a-configuration)** > > `POST /api/v1/lightstep/configuration/validate` > **[Delete a configuration](/api/rest/servicenow-cloud-observability-api/delete-a-configuration)** > > `DELETE /api/v1/lightstep/configurations` # Snyk API Source: https://docs.cortex.io/api/rest/integrations/snyk Use these operations to interact with the [Snyk integration](/ingesting-data-into-cortex/integrations/snyk) in Cortex. ### Required permissions Your API key must have the `Configure integrations` permission. ## Operations > **[Retrieve a configuration](/api/rest/snyk-api/retrieve-a-configuration)** > > `GET /api/v1/snyk/default-configuration` > **[Add a configuration](/api/rest/snyk-api/add-a-configuration)** > > `POST /api/v1/snyk/configuration` > **[Update the existing configuration](/api/rest/snyk-api/update-the-existing-configuration)** > > `PUT /api/v1/snyk/configuration` > **[Validate a configuration](/api/rest/snyk-api/validate-a-configuration)** > > `POST /api/v1/snyk/configuration/validate` > **[Delete a configuration](/api/rest/snyk-api/delete-a-configuration)** > > `DELETE /api/v1/snyk/configurations` # SonarQube API Source: https://docs.cortex.io/api/rest/integrations/sonarqube Use these operations to interact with the [SonarQube integration](/ingesting-data-into-cortex/integrations/sonarqube) in Cortex. ### Required permissions Your API key must have the `Configure integrations` permission. ## Operations > **[Retrieve configurations](/api/rest/sonarqube-api/retrieve-configurations)** > > `GET /api/v1/sonarqube/configurations` > **[Retrieve default configuration](/api/rest/sonarqube-api/retrieve-default-configuration)** > > `GET /api/v1/sonarqube/default-configuration` > **[Retrieve a configuration](/api/rest/sonarqube-api/retrieve-a-configuration)** > > `GET /api/v1/sonarqube/configuration/{alias}` > **[Add multiple configurations](/api/rest/sonarqube-api/add-multiple-configurations)** > > `POST /api/v1/sonarqube/configurations` > **[Add a single configuration](/api/rest/sonarqube-api/add-a-single-configuration)** > > `POST /api/v1/sonarqube/configuration` > **[Validate all configurations](/api/rest/sonarqube-api/validate-all-configurations)** > > `POST /api/v1/sonarqube/configuration/validate` > **[Validate a configuration](/api/rest/sonarqube-api/validate-a-configuration)** > > `POST /api/v1/sonarqube/configuration/validate/{alias}` > **[Update a configuration](/api/rest/sonarqube-api/update-a-configuration)** > > `PUT /api/v1/sonarqube/configuration/{alias}` > **[Delete a configuration](/api/rest/sonarqube-api/delete-a-configuration)** > > `DELETE /api/v1/sonarqube/configuration/{alias}` > **[Delete all configurations](/api/rest/sonarqube-api/delete-all-configurations)** > > `DELETE /api/v1/sonarqube/configurations` # Splunk Observability Cloud API Source: https://docs.cortex.io/api/rest/integrations/splunk-observability-cloud Use these operations to interact with the [Splunk Observability Cloud integration](/api/rest/integrations/splunk-observability-cloud) in Cortex. ### Required permissions Your API key must have the `Configure integrations` permission. ## Operations > **[Retrieve a configuration](/api/rest/splunk-observability-cloud-api/retrieve-a-configuration)** > > `GET /api/v1/signalfx/default-configuration` > **[Add a configuration](/api/rest/splunk-observability-cloud-api/add-a-configuration)** > > `POST /api/v1/signalfx/configuration` > **[Update the existing configuration](/api/rest/splunk-observability-cloud-api/update-the-existing-configuration)** > > `PUT /api/v1/signalfx/configuration` > **[Validate a configuration](/api/rest/splunk-observability-cloud-api/validate-a-configuration)** > > `POST /api/v1/signalfx/configuration/validate` > **[Delete a configuration](/api/rest/splunk-observability-cloud-api/delete-a-configuration)** > > `DELETE /api/v1/signalfx/configurations` # Splunk On Call API Source: https://docs.cortex.io/api/rest/integrations/splunk-on-call Use these operations to interact with the [Splunk On Call integration](/api/rest/integrations/splunk-on-call) in Cortex. ### Required permissions Your API key must have the `Configure integrations` permission. ## Operations > **[Retrieve a configuration](/api/rest/splunk-on-call-api/retrieve-a-configuration)** > > `GET /api/v1/victorops/default-configuration` > **[Add a configuration](/api/rest/splunk-on-call-api/add-a-configuration)** > > `POST /api/v1/victorops/configuration` > **[Update the existing configuration](/api/rest/splunk-on-call-api/update-the-existing-configuration)** > > `PUT /api/v1/victorops/configuration` > **[Validate a configuration](/api/rest/splunk-on-call-api/validate-a-configuration)** > > `POST /api/v1/victorops/configuration/validate` > **[Delete a configuration](/api/rest/splunk-on-call-api/delete-a-configuration)** > > `DELETE /api/v1/victorops/configurations` # Sumo Logic API Source: https://docs.cortex.io/api/rest/integrations/sumologic Use these operations to interact with the [Sumo Logic integration](/ingesting-data-into-cortex/integrations/sumologic) in Cortex. ### Required permissions Your API key must have the `Configure integrations` permission. ## Operations > **[Retrieve a configuration](/api/rest/sumo-logic-api/retrieve-a-configuration)** > > `GET /api/v1/sumologic/default-configuration` > **[Add a configuration](/api/rest/sumo-logic-api/add-a-configuration)** > > `POST /api/v1/sumologic/configuration` > **[Update the existing configuration](/api/rest/sumo-logic-api/update-the-existing-configuration)** > > `PUT /api/v1/sumologic/configuration` > **[Validate a configuration](/api/rest/sumo-logic-api/validate-a-configuration)** > > `POST /api/v1/sumologic/configuration/validate` > **[Delete a configuration](/api/rest/sumo-logic-api/delete-a-configuration)** > > `DELETE /api/v1/sumologic/configurations` # Veracode API Source: https://docs.cortex.io/api/rest/integrations/veracode Use these operations to interact with the [Veracode integration](/ingesting-data-into-cortex/integrations/veracode) in Cortex. ### Required permissions Your API key must have the `Configure integrations` permission. ## Operations > **[Retrieve a configuration](/api/rest/veracode-api/retrieve-a-configuration)** > > `GET /api/v1/veracode/default-configuration` > **[Add a configuration](/api/rest/veracode-api/add-a-configuration)** > > `POST /api/v1/veracode/configuration` > **[Update the existing configuration](/api/rest/veracode-api/update-the-existing-configuration)** > > `PUT /api/v1/veracode/configuration` > **[Validate a configuration](/api/rest/veracode-api/validate-a-configuration)** > > `POST /api/v1/veracode/configuration/validate` > **[Delete a configuration](/api/rest/veracode-api/delete-a-configuration)** > > `DELETE /api/v1/veracode/configurations` # Wiz API Source: https://docs.cortex.io/api/rest/integrations/wiz Use these operations to interact with the [Wiz integration](/ingesting-data-into-cortex/integrations/wiz) in Cortex. ### Required permissions Your API key must have the `Configure integrations` permission. ## Operations > **[Retrieve a configuration](/api/rest/wiz-api/retrieve-a-configuration)** > > `GET /api/v1/wiz/default-configuration` > **[Add a configuration](/api/rest/wiz-api/add-a-configuration)** > > `POST /api/v1/wiz/configuration` > **[Update the existing configuration](/api/rest/wiz-api/update-the-existing-configuration)** > > `PUT /api/v1/wiz/configuration` > **[Validate a configuration](/api/rest/wiz-api/validate-a-configuration)** > > `POST /api/v1/wiz/configuration/validate` > **[Delete a configuration](/api/rest/wiz-api/delete-a-configuration)** > > `DELETE /api/v1/wiz/configurations` # Workday API Source: https://docs.cortex.io/api/rest/integrations/workday Use these operations to interact with the [Workday integration](/ingesting-data-into-cortex/integrations/workday) in Cortex. ### Required permissions Your API key must have the `Configure integrations` permission. ## Operations > **[Retrieve a configuration](/api/rest/workday-api/retrieve-a-configuration)** > > `GET /api/v1/workday/default-configuration` > **[Add a configuration](/api/rest/workday-api/add-a-configuration)** > > `POST /api/v1/workday/configuration` > **[Update the existing configuration](/api/rest/workday-api/update-the-existing-configuration)** > > `PUT /api/v1/workday/configuration` > **[Validate a configuration](/api/rest/workday-api/validate-a-configuration)** > > `POST /api/v1/workday/configuration/validate` > **[Delete a configuration](/api/rest/workday-api/delete-a-configuration)** > > `DELETE /api/v1/workday/configurations` # xMatters API Source: https://docs.cortex.io/api/rest/integrations/xmatters Use these operations to interact with the [xMatters integration](/ingesting-data-into-cortex/integrations/xmatters) in Cortex. ### Required permissions Your API key must have the `Configure integrations` permission. ## Operations > **[Retrieve a configuration](/api/rest/xmatters-api/retrieve-a-configuration)** > > `GET /api/v1/xmatters/default-configuration` > **[Add a configuration](/api/rest/xmatters-api/add-a-configuration)** > > `POST /api/v1/xmatters/configuration` > **[Update the existing configuration](/api/rest/xmatters-api/update-the-existing-configuration)** > > `PUT /api/v1/xmatters/configuration` > **[Validate a configuration](/api/rest/xmatters-api/validate-a-configuration)** > > `POST /api/v1/xmatters/configuration/validate` > **[Delete a configuration](/api/rest/xmatters-api/delete-a-configuration)** > > `DELETE /api/v1/xmatters/configurations` # IP Allowlist Source: https://docs.cortex.io/api/rest/ip-allowlist Use these operations to interact with the [IP allowlist](/configure/settings/ip-allowlist) in Cortex. ### Required permissions Your API key must have the `Configure IP allowlist` permission. ## Operations > **[Gets allowlist of IP addresses & ranges](/api/rest/ip-allowlist/gets-allowlist-of-ip-addresses-&-ranges)** > > `GET /api/v1/ip-allowlist` > **[Validates allowlist of IP addresses & ranges](/api/rest/ip-allowlist/validates-allowlist-of-ip-addresses-&-ranges)** > > `POST /api/v1/ip-allowlist/validate` > **[Replace existing allowlist with provided list of IP addresses & ranges](/api/rest/ip-allowlist/replace-existing-allowlist-with-provided-list-of-ip-addresses-&-ranges)** > > `PUT /api/v1/ip-allowlist` # Gets allowlist of IP addresses & ranges Source: https://docs.cortex.io/api/rest/ip-allowlist/gets-allowlist-of-ip-addresses-&-ranges /openapi/cortex_swagger.json get /api/v1/ip-allowlist # Replace existing allowlist with provided list of IP addresses & ranges Source: https://docs.cortex.io/api/rest/ip-allowlist/replace-existing-allowlist-with-provided-list-of-ip-addresses-&-ranges /openapi/cortex_swagger.json put /api/v1/ip-allowlist # Validates allowlist of IP addresses & ranges Source: https://docs.cortex.io/api/rest/ip-allowlist/validates-allowlist-of-ip-addresses-&-ranges /openapi/cortex_swagger.json post /api/v1/ip-allowlist/validate # Add a single configuration Source: https://docs.cortex.io/api/rest/jenkins-api/add-a-single-configuration /openapi/cortex_swagger.json post /api/v1/jenkins/configuration # Add multiple configurations Source: https://docs.cortex.io/api/rest/jenkins-api/add-multiple-configurations /openapi/cortex_swagger.json post /api/v1/jenkins/configurations # Delete a configuration Source: https://docs.cortex.io/api/rest/jenkins-api/delete-a-configuration /openapi/cortex_swagger.json delete /api/v1/jenkins/configuration/{alias} # Delete all configurations Source: https://docs.cortex.io/api/rest/jenkins-api/delete-all-configurations /openapi/cortex_swagger.json delete /api/v1/jenkins/configurations # Retrieve a configuration Source: https://docs.cortex.io/api/rest/jenkins-api/retrieve-a-configuration /openapi/cortex_swagger.json get /api/v1/jenkins/configuration/{alias} # Retrieve configurations Source: https://docs.cortex.io/api/rest/jenkins-api/retrieve-configurations /openapi/cortex_swagger.json get /api/v1/jenkins/configurations # Retrieve default configuration Source: https://docs.cortex.io/api/rest/jenkins-api/retrieve-default-configuration /openapi/cortex_swagger.json get /api/v1/jenkins/default-configuration # Update a configuration Source: https://docs.cortex.io/api/rest/jenkins-api/update-a-configuration /openapi/cortex_swagger.json put /api/v1/jenkins/configuration/{alias} WARNING: Updating aliases for configurations or changing the default configuration could cause entity YAMLs that use this integration to break. # Validate a configuration Source: https://docs.cortex.io/api/rest/jenkins-api/validate-a-configuration /openapi/cortex_swagger.json post /api/v1/jenkins/configuration/validate/{alias} # Validate all configurations Source: https://docs.cortex.io/api/rest/jenkins-api/validate-all-configurations /openapi/cortex_swagger.json post /api/v1/jenkins/configuration/validate # Add a single configuration Source: https://docs.cortex.io/api/rest/jira-api/add-a-single-configuration /openapi/cortex_swagger.json post /api/v1/jira/configuration # Add multiple configurations Source: https://docs.cortex.io/api/rest/jira-api/add-multiple-configurations /openapi/cortex_swagger.json post /api/v1/jira/configurations # Delete a configuration Source: https://docs.cortex.io/api/rest/jira-api/delete-a-configuration /openapi/cortex_swagger.json delete /api/v1/jira/configuration/{alias} # Delete all configurations Source: https://docs.cortex.io/api/rest/jira-api/delete-all-configurations /openapi/cortex_swagger.json delete /api/v1/jira/configurations # Retrieve a configuration Source: https://docs.cortex.io/api/rest/jira-api/retrieve-a-configuration /openapi/cortex_swagger.json get /api/v1/jira/configuration/{alias} # Retrieve configurations Source: https://docs.cortex.io/api/rest/jira-api/retrieve-configurations /openapi/cortex_swagger.json get /api/v1/jira/configurations # Retrieve default configuration Source: https://docs.cortex.io/api/rest/jira-api/retrieve-default-configuration /openapi/cortex_swagger.json get /api/v1/jira/default-configuration # Update a configuration Source: https://docs.cortex.io/api/rest/jira-api/update-a-configuration /openapi/cortex_swagger.json put /api/v1/jira/configuration/{alias} WARNING: Updating aliases for configurations or changing the default configuration could cause entity YAMLs that use this integration to break. # Validate a configuration Source: https://docs.cortex.io/api/rest/jira-api/validate-a-configuration /openapi/cortex_swagger.json post /api/v1/jira/configuration/validate/{alias} # Validate all configurations Source: https://docs.cortex.io/api/rest/jira-api/validate-all-configurations /openapi/cortex_swagger.json post /api/v1/jira/configuration/validate # Get Kubernetes resource details for an entity Source: https://docs.cortex.io/api/rest/kubernetes-api/get-kubernetes-resource-details-for-an-entity /openapi/cortex_swagger.json get /api/v1/catalog/{tagOrId}/k8s Returns cached Kubernetes resource details for the specified entity. This endpoint serves cached data only and does not make live Kubernetes API calls. # Add a single configuration Source: https://docs.cortex.io/api/rest/launchdarkly-api/add-a-single-configuration /openapi/cortex_swagger.json post /api/v1/launchdarkly/configuration # Add multiple configurations Source: https://docs.cortex.io/api/rest/launchdarkly-api/add-multiple-configurations /openapi/cortex_swagger.json post /api/v1/launchdarkly/configurations # Delete a configuration Source: https://docs.cortex.io/api/rest/launchdarkly-api/delete-a-configuration /openapi/cortex_swagger.json delete /api/v1/launchdarkly/configuration/{alias} # Delete all configurations Source: https://docs.cortex.io/api/rest/launchdarkly-api/delete-all-configurations /openapi/cortex_swagger.json delete /api/v1/launchdarkly/configurations # Retrieve a configuration Source: https://docs.cortex.io/api/rest/launchdarkly-api/retrieve-a-configuration /openapi/cortex_swagger.json get /api/v1/launchdarkly/configuration/{alias} # Retrieve configurations Source: https://docs.cortex.io/api/rest/launchdarkly-api/retrieve-configurations /openapi/cortex_swagger.json get /api/v1/launchdarkly/configurations # Retrieve default configuration Source: https://docs.cortex.io/api/rest/launchdarkly-api/retrieve-default-configuration /openapi/cortex_swagger.json get /api/v1/launchdarkly/default-configuration # Update a configuration Source: https://docs.cortex.io/api/rest/launchdarkly-api/update-a-configuration /openapi/cortex_swagger.json put /api/v1/launchdarkly/configuration/{alias} WARNING: Updating aliases for configurations or changing the default configuration could cause entity YAMLs that use this integration to break. # Validate a configuration Source: https://docs.cortex.io/api/rest/launchdarkly-api/validate-a-configuration /openapi/cortex_swagger.json post /api/v1/launchdarkly/configuration/validate/{alias} # Validate all configurations Source: https://docs.cortex.io/api/rest/launchdarkly-api/validate-all-configurations /openapi/cortex_swagger.json post /api/v1/launchdarkly/configuration/validate # Add a configuration Source: https://docs.cortex.io/api/rest/mend-sast-api/add-a-configuration /openapi/cortex_swagger.json post /api/v1/mend/sast/configuration # Delete a configuration Source: https://docs.cortex.io/api/rest/mend-sast-api/delete-a-configuration /openapi/cortex_swagger.json delete /api/v1/mend/sast/configurations # Retrieve a configuration Source: https://docs.cortex.io/api/rest/mend-sast-api/retrieve-a-configuration /openapi/cortex_swagger.json get /api/v1/mend/sast/default-configuration # Update the existing configuration Source: https://docs.cortex.io/api/rest/mend-sast-api/update-the-existing-configuration /openapi/cortex_swagger.json put /api/v1/mend/sast/configuration # Validate a configuration Source: https://docs.cortex.io/api/rest/mend-sast-api/validate-a-configuration /openapi/cortex_swagger.json post /api/v1/mend/sast/configuration/validate # Add a configuration Source: https://docs.cortex.io/api/rest/mend-sca-api/add-a-configuration /openapi/cortex_swagger.json post /api/v1/mend/sca/configuration # Delete a configuration Source: https://docs.cortex.io/api/rest/mend-sca-api/delete-a-configuration /openapi/cortex_swagger.json delete /api/v1/mend/sca/configurations # Retrieve a configuration Source: https://docs.cortex.io/api/rest/mend-sca-api/retrieve-a-configuration /openapi/cortex_swagger.json get /api/v1/mend/sca/default-configuration # Update the existing configuration Source: https://docs.cortex.io/api/rest/mend-sca-api/update-the-existing-configuration /openapi/cortex_swagger.json put /api/v1/mend/sca/configuration # Validate a configuration Source: https://docs.cortex.io/api/rest/mend-sca-api/validate-a-configuration /openapi/cortex_swagger.json post /api/v1/mend/sca/configuration/validate # Add a single configuration Source: https://docs.cortex.io/api/rest/new-relic-api/add-a-single-configuration /openapi/cortex_swagger.json post /api/v1/newrelic/configuration # Add multiple configurations Source: https://docs.cortex.io/api/rest/new-relic-api/add-multiple-configurations /openapi/cortex_swagger.json post /api/v1/newrelic/configurations # Delete a configuration Source: https://docs.cortex.io/api/rest/new-relic-api/delete-a-configuration /openapi/cortex_swagger.json delete /api/v1/newrelic/configuration/{alias} # Delete all configurations Source: https://docs.cortex.io/api/rest/new-relic-api/delete-all-configurations /openapi/cortex_swagger.json delete /api/v1/newrelic/configurations # Retrieve a configuration Source: https://docs.cortex.io/api/rest/new-relic-api/retrieve-a-configuration /openapi/cortex_swagger.json get /api/v1/newrelic/configuration/{alias} # Retrieve configurations Source: https://docs.cortex.io/api/rest/new-relic-api/retrieve-configurations /openapi/cortex_swagger.json get /api/v1/newrelic/configurations # Retrieve default configuration Source: https://docs.cortex.io/api/rest/new-relic-api/retrieve-default-configuration /openapi/cortex_swagger.json get /api/v1/newrelic/default-configuration # Update a configuration Source: https://docs.cortex.io/api/rest/new-relic-api/update-a-configuration /openapi/cortex_swagger.json put /api/v1/newrelic/configuration/{alias} WARNING: Updating aliases for configurations or changing the default configuration could cause entity YAMLs that use this integration to break. # Validate a configuration Source: https://docs.cortex.io/api/rest/new-relic-api/validate-a-configuration /openapi/cortex_swagger.json post /api/v1/newrelic/configuration/validate/{alias} # Validate all configurations Source: https://docs.cortex.io/api/rest/new-relic-api/validate-all-configurations /openapi/cortex_swagger.json post /api/v1/newrelic/configuration/validate # Notification Logs Source: https://docs.cortex.io/api/rest/notification-logs Use these operations to interact with [notification logs](/configure/settings/notifications/logs) in Cortex. ### Required permissions Your API key must have the `View notification logs` permission. ## Operations > **[Retrieve notification logs](/api/rest/notification-logs/retrieve-notification-logs)** > > `GET /api/v1/notifications/logs` > **[Retrieve notification runs](/api/rest/notification-logs/retrieve-notification-runs)** > > `GET /api/v1/notifications/logs/run` # Retrieve notification logs Source: https://docs.cortex.io/api/rest/notification-logs/retrieve-notification-logs /openapi/cortex_swagger.json get /api/v1/notifications/logs Retrieve notification logs based on the provided filters. API key must have the `View Notification logs` permission. # Retrieve notification runs Source: https://docs.cortex.io/api/rest/notification-logs/retrieve-notification-runs /openapi/cortex_swagger.json get /api/v1/notifications/logs/run Retrieve notification runs based on the provided filters. API key must have the `View Notification logs` permission. # Add a configuration Source: https://docs.cortex.io/api/rest/okta-api/add-a-configuration /openapi/cortex_swagger.json post /api/v1/okta/configuration # Delete a configuration Source: https://docs.cortex.io/api/rest/okta-api/delete-a-configuration /openapi/cortex_swagger.json delete /api/v1/okta/configurations # Retrieve a configuration Source: https://docs.cortex.io/api/rest/okta-api/retrieve-a-configuration /openapi/cortex_swagger.json get /api/v1/okta/default-configuration # Update the existing configuration Source: https://docs.cortex.io/api/rest/okta-api/update-the-existing-configuration /openapi/cortex_swagger.json put /api/v1/okta/configuration # Validate a configuration Source: https://docs.cortex.io/api/rest/okta-api/validate-a-configuration /openapi/cortex_swagger.json post /api/v1/okta/configuration/validate # On call Source: https://docs.cortex.io/api/rest/on-call Use these operations to interact with on-call information on [entities](/ingesting-data-into-cortex/entities-overview/entities) in Cortex. ### Required permissions * Your API key must have the `Edit entities` permission. ## Operations > **[Retrieve current on-call for entity](/api/rest/on-call/retrieve-current-on-call-for-entity)** > > `GET /api/v1/catalog/{tagOrId}/integrations/oncall/current` > **[Retrieve on-call registration for entity](/api/rest/on-call/retrieve-on-call-registration-for-entity)** > > `GET /api/v1/catalog/{tagOrId}/integrations/oncall/registration` # Retrieve current on-call for entity Source: https://docs.cortex.io/api/rest/on-call/retrieve-current-on-call-for-entity /openapi/cortex_swagger.json get /api/v1/catalog/{tagOrId}/integrations/oncall/current # Retrieve on-call registration for entity Source: https://docs.cortex.io/api/rest/on-call/retrieve-on-call-registration-for-entity /openapi/cortex_swagger.json get /api/v1/catalog/{tagOrId}/integrations/oncall/registration # Add a configuration Source: https://docs.cortex.io/api/rest/opsgenie-api/add-a-configuration /openapi/cortex_swagger.json post /api/v1/opsgenie/configuration # Delete a configuration Source: https://docs.cortex.io/api/rest/opsgenie-api/delete-a-configuration /openapi/cortex_swagger.json delete /api/v1/opsgenie/configurations # Retrieve a configuration Source: https://docs.cortex.io/api/rest/opsgenie-api/retrieve-a-configuration /openapi/cortex_swagger.json get /api/v1/opsgenie/default-configuration # Update the existing configuration Source: https://docs.cortex.io/api/rest/opsgenie-api/update-the-existing-configuration /openapi/cortex_swagger.json put /api/v1/opsgenie/configuration # Validate a configuration Source: https://docs.cortex.io/api/rest/opsgenie-api/validate-a-configuration /openapi/cortex_swagger.json post /api/v1/opsgenie/configuration/validate # Packages Source: https://docs.cortex.io/api/rest/packages Use these operations to interact with packages in Cortex. ### Required permissions Your API key must have the `Edit entities` permission. ## Operations > **[List packages](/api/rest/packages/list-packages)** > > `GET /api/v1/catalog/{tagOrId}/packages` > **[\[csharp\] Upload Nuget csproj](/api/rest/packages/\[csharp]-upload-nuget-csproj)** > > `POST /api/v1/catalog/{tagOrId}/packages/dotnet/nuget/csproj` > **[\[csharp\] Upload Nuget packages.lock.json](/api/rest/packages/\[csharp]-upload-nuget-packageslockjson)** > > `POST /api/v1/catalog/{tagOrId}/packages/dotnet/nuget/packages-lock` > **[\[csharp\] Delete Nuget package](/api/rest/packages/\[csharp]-delete-nuget-package)** > > `DELETE /api/v1/catalog/{tagOrId}/packages/dotnet/nuget` > **[\[golang\] Upload go.sum](/api/rest/packages/\[golang]-upload-gosum)** > > `POST /api/v1/catalog/{tagOrId}/packages/go/gosum` > **[\[go\] Delete Go package](/api/rest/packages/\[go]-delete-go-package)** > > `DELETE /api/v1/catalog/{tagOrId}/packages/go` > **[\[java\] Upload single Java package](/api/rest/packages/\[java]-upload-single-java-package)** > > `POST /api/v1/catalog/{tagOrId}/packages/java` > **[\[java\] Upload multiple Java packages](/api/rest/packages/\[java]-upload-multiple-java-packages)** > > `POST /api/v1/catalog/{tagOrId}/packages/java/bulk` > **[\[java\] Upload maven pom.xml](/api/rest/packages/\[java]-upload-maven-pomxml)** > > `POST /api/v1/catalog/{tagOrId}/packages/java/maven-pom` > **[\[java\] Delete Java package](/api/rest/packages/\[java]-delete-java-package)** > > `DELETE /api/v1/catalog/{tagOrId}/packages/java` > **[\[js\] Upload NPM/Yarn/PNPM package.json](/api/rest/packages/\[js]-upload-npmyarnpnpm-packagejson)** > > `POST /api/v1/catalog/{tagOrId}/packages/node/package-json` > **[\[js\] Upload NPM package-lock.json](/api/rest/packages/\[js]-upload-npm-package-lockjson)** > > `POST /api/v1/catalog/{tagOrId}/packages/node/package-lock` > **[\[node\] Delete Node package](/api/rest/packages/\[node]-delete-node-package)** > > `DELETE /api/v1/catalog/{tagOrId}/packages/node` > **[\[js\] Upload pnpm-lock.yaml](/api/rest/packages/\[js]-upload-pnpm-lockyaml)** > > `POST /api/v1/catalog/{tagOrId}/packages/node/pnpm-lock` > **[\[js\] Upload yarn.lock](/api/rest/packages/\[js]-upload-yarnlock)** > > `POST /api/v1/catalog/{tagOrId}/packages/node/yarn-lock` > **[\[python\] Upload pipfile.lock](/api/rest/packages/\[python]-upload-pipfilelock)** > > `POST /api/v1/catalog/{tagOrId}/packages/python/pipfile` > **[\[python\] Upload requirements.txt](/api/rest/packages/\[python]-upload-requirementstxt)** > > `POST /api/v1/catalog/{tagOrId}/packages/python/requirements` > [!WARNING] > > Only exact version specifiers (`==`) are supported in `requirements.txt` files. Other version specifiers such as `>=`, `<=`, `~=`, and `!=` are ignored when parsing the file. Packages specified without an exact version will be ingested without a version value. > **[\[python\] Delete Python package](/api/rest/packages/\[python]-delete-python-package)** > > `DELETE /api/v1/catalog/{tagOrId}/packages/python` # [csharp] Delete Nuget package Source: https://docs.cortex.io/api/rest/packages/[csharp]-delete-nuget-package /openapi/cortex_swagger.json delete /api/v1/catalog/{tagOrId}/packages/dotnet/nuget # [csharp] Upload Nuget csproj Source: https://docs.cortex.io/api/rest/packages/[csharp]-upload-nuget-csproj /openapi/cortex_swagger.json post /api/v1/catalog/{tagOrId}/packages/dotnet/nuget/csproj # [csharp] Upload Nuget packages.lock.json Source: https://docs.cortex.io/api/rest/packages/[csharp]-upload-nuget-packageslockjson /openapi/cortex_swagger.json post /api/v1/catalog/{tagOrId}/packages/dotnet/nuget/packages-lock # [go] Delete Go package Source: https://docs.cortex.io/api/rest/packages/[go]-delete-go-package /openapi/cortex_swagger.json delete /api/v1/catalog/{tagOrId}/packages/go # [golang] Upload go.sum Source: https://docs.cortex.io/api/rest/packages/[golang]-upload-gosum /openapi/cortex_swagger.json post /api/v1/catalog/{tagOrId}/packages/go/gosum # [java] Delete Java package Source: https://docs.cortex.io/api/rest/packages/[java]-delete-java-package /openapi/cortex_swagger.json delete /api/v1/catalog/{tagOrId}/packages/java # [java] Upload maven pom.xml Source: https://docs.cortex.io/api/rest/packages/[java]-upload-maven-pomxml /openapi/cortex_swagger.json post /api/v1/catalog/{tagOrId}/packages/java/maven-pom # [java] Upload multiple Java packages Source: https://docs.cortex.io/api/rest/packages/[java]-upload-multiple-java-packages /openapi/cortex_swagger.json post /api/v1/catalog/{tagOrId}/packages/java/bulk # [java] Upload single Java package Source: https://docs.cortex.io/api/rest/packages/[java]-upload-single-java-package /openapi/cortex_swagger.json post /api/v1/catalog/{tagOrId}/packages/java # [js] Upload NPM package-lock.json Source: https://docs.cortex.io/api/rest/packages/[js]-upload-npm-package-lockjson /openapi/cortex_swagger.json post /api/v1/catalog/{tagOrId}/packages/node/package-lock # [js] Upload NPM/Yarn/PNPM package.json Source: https://docs.cortex.io/api/rest/packages/[js]-upload-npmyarnpnpm-packagejson /openapi/cortex_swagger.json post /api/v1/catalog/{tagOrId}/packages/node/package-json # [js] Upload pnpm-lock.yaml Source: https://docs.cortex.io/api/rest/packages/[js]-upload-pnpm-lockyaml /openapi/cortex_swagger.json post /api/v1/catalog/{tagOrId}/packages/node/pnpm-lock # [js] Upload yarn.lock Source: https://docs.cortex.io/api/rest/packages/[js]-upload-yarnlock /openapi/cortex_swagger.json post /api/v1/catalog/{tagOrId}/packages/node/yarn-lock # [node] Delete Node package Source: https://docs.cortex.io/api/rest/packages/[node]-delete-node-package /openapi/cortex_swagger.json delete /api/v1/catalog/{tagOrId}/packages/node # [python] Delete Python package Source: https://docs.cortex.io/api/rest/packages/[python]-delete-python-package /openapi/cortex_swagger.json delete /api/v1/catalog/{tagOrId}/packages/python # [python] Upload pipfile.lock Source: https://docs.cortex.io/api/rest/packages/[python]-upload-pipfilelock /openapi/cortex_swagger.json post /api/v1/catalog/{tagOrId}/packages/python/pipfile # [python] Upload requirements.txt Source: https://docs.cortex.io/api/rest/packages/[python]-upload-requirementstxt /openapi/cortex_swagger.json post /api/v1/catalog/{tagOrId}/packages/python/requirements # List packages Source: https://docs.cortex.io/api/rest/packages/list-packages /openapi/cortex_swagger.json get /api/v1/catalog/{tagOrId}/packages # Add a configuration Source: https://docs.cortex.io/api/rest/pagerduty-api/add-a-configuration /openapi/cortex_swagger.json post /api/v1/pagerduty/configuration # Delete a configuration Source: https://docs.cortex.io/api/rest/pagerduty-api/delete-a-configuration /openapi/cortex_swagger.json delete /api/v1/pagerduty/configurations # Retrieve a configuration Source: https://docs.cortex.io/api/rest/pagerduty-api/retrieve-a-configuration /openapi/cortex_swagger.json get /api/v1/pagerduty/default-configuration # Update the existing configuration Source: https://docs.cortex.io/api/rest/pagerduty-api/update-the-existing-configuration /openapi/cortex_swagger.json put /api/v1/pagerduty/configuration # Validate a configuration Source: https://docs.cortex.io/api/rest/pagerduty-api/validate-a-configuration /openapi/cortex_swagger.json post /api/v1/pagerduty/configuration/validate # Plugins Source: https://docs.cortex.io/api/rest/plugins Use these operations to interact with [plugins](/streamline/plugins) in Cortex. ### Required permissions Your API key must have the `Edit plugins` permission for write operations (create, update, and delete). For read endpoints, your API key's effective role must be greater than or equal to the plugin's `minimumRoleRequired` setting — if it is not, read endpoints will return `403 Forbidden` for existing plugins or an empty result set. ## Operations > **[Get all plugins](/api/rest/plugins/get-all-plugins)** > > `GET /api/v1/plugins` > **[Get plugin by tag](/api/rest/plugins/get-plugin-by-tag)** > > `GET /api/v1/plugins/{tag}` > **[Create a plugin](/api/rest/plugins/create-a-plugin)** > > `POST /api/v1/plugins` > **[Replace a plugin](/api/rest/plugins/replace-a-plugin)** > > `PUT /api/v1/plugins/{tag}` > **[Delete a plugin](/api/rest/plugins/delete-a-plugin)** > > `DELETE /api/v1/plugins/{tag}` # Create a plugin Source: https://docs.cortex.io/api/rest/plugins/create-a-plugin /openapi/cortex_swagger.json post /api/v1/plugins Create a new plugin # Delete a plugin Source: https://docs.cortex.io/api/rest/plugins/delete-a-plugin /openapi/cortex_swagger.json delete /api/v1/plugins/{tag} Delete a plugin by tag # Get all plugins Source: https://docs.cortex.io/api/rest/plugins/get-all-plugins /openapi/cortex_swagger.json get /api/v1/plugins Retrieve a list of all plugins, excluding drafts # Get plugin by tag Source: https://docs.cortex.io/api/rest/plugins/get-plugin-by-tag /openapi/cortex_swagger.json get /api/v1/plugins/{tag} Retrieve the metadata of a plugin by tag # Replace a plugin Source: https://docs.cortex.io/api/rest/plugins/replace-a-plugin /openapi/cortex_swagger.json put /api/v1/plugins/{tag} Replace an existing plugin by tag # Add a single configuration Source: https://docs.cortex.io/api/rest/prometheus-api/add-a-single-configuration /openapi/cortex_swagger.json post /api/v1/prometheus/configuration # Add multiple configurations Source: https://docs.cortex.io/api/rest/prometheus-api/add-multiple-configurations /openapi/cortex_swagger.json post /api/v1/prometheus/configurations # Delete a configuration Source: https://docs.cortex.io/api/rest/prometheus-api/delete-a-configuration /openapi/cortex_swagger.json delete /api/v1/prometheus/configuration/{alias} # Delete all configurations Source: https://docs.cortex.io/api/rest/prometheus-api/delete-all-configurations /openapi/cortex_swagger.json delete /api/v1/prometheus/configurations # Retrieve a configuration Source: https://docs.cortex.io/api/rest/prometheus-api/retrieve-a-configuration /openapi/cortex_swagger.json get /api/v1/prometheus/configuration/{alias} # Retrieve configurations Source: https://docs.cortex.io/api/rest/prometheus-api/retrieve-configurations /openapi/cortex_swagger.json get /api/v1/prometheus/configurations # Retrieve default configuration Source: https://docs.cortex.io/api/rest/prometheus-api/retrieve-default-configuration /openapi/cortex_swagger.json get /api/v1/prometheus/default-configuration # Update a configuration Source: https://docs.cortex.io/api/rest/prometheus-api/update-a-configuration /openapi/cortex_swagger.json put /api/v1/prometheus/configuration/{alias} WARNING: Updating aliases for configurations or changing the default configuration could cause entity YAMLs that use this integration to break. # Validate a configuration Source: https://docs.cortex.io/api/rest/prometheus-api/validate-a-configuration /openapi/cortex_swagger.json post /api/v1/prometheus/configuration/validate/{alias} # Validate all configurations Source: https://docs.cortex.io/api/rest/prometheus-api/validate-all-configurations /openapi/cortex_swagger.json post /api/v1/prometheus/configuration/validate # Queries Source: https://docs.cortex.io/api/rest/queries Use these operations to interact with [CQL queries](/standardize/cql) in Cortex. > [!WARNING] > > Starting November 10, 2026, `POST /api/v1/queries` no longer runs a query against every entity in your catalog. Pass up to 100 tags or Cortex IDs in `entities`, or page through the catalog with `pageSize` and `pageToken`. A request without `entities` runs against the first page of up to 1,000 entities, and its `nextPageToken` reads the next page. ### Required permissions Edit entities: Your API key must have the `Enable Query builder` permission. ## Operations > **[Retrieve query results](/api/rest/queries/retrieve-query-results)** > > `GET /api/v1/queries/{jobId}` > **[Run query](/api/rest/queries/run-query)** > > `POST /api/v1/queries` # Retrieve query results Source: https://docs.cortex.io/api/rest/queries/retrieve-query-results /openapi/cortex_swagger.json get /api/v1/queries/{jobId} Retrieve the status and results of a CQL query # Run query Source: https://docs.cortex.io/api/rest/queries/run-query /openapi/cortex_swagger.json post /api/v1/queries Run a CQL query against up to 100 `entities`, or against one page of the catalog with `pageSize` and `pageToken`. A request with neither runs against every entity in the catalog. Starting November 10, 2026, it runs against the first page only, and the response's `nextPageToken` reads the next page. For more information about the types of queries you can run, take a look at our CQL Explorer in the app. # Recommendations Source: https://docs.cortex.io/api/rest/recommendations PRIVATE BETA Use these operations to review [ownership recommendations](/ingesting-data-into-cortex/entities-overview/entities/ownership/assigning-owners-to-entities#assigning-ownership-via-cortex-recommendations) in Cortex. Ownership recommendations are in [private beta](/resources/beta#ownership-recommendations-private-beta). ### Required permissions To accept, reject, or restore a recommendation, your API key must be able to edit the recommendation's entity. ## Operations > **[List ownership recommendations](/api/rest/recommendations/list-ownership-recommendations)** > > `GET /api/v1/recommendations/ownership` > **[List entities with ownership recommendations](/api/rest/recommendations/list-entities-with-ownership-recommendations)** > > `GET /api/v1/recommendations/ownership/entities` > **[Accept an ownership recommendation](/api/rest/recommendations/accept-an-ownership-recommendation)** > > `POST /api/v1/recommendations/ownership/{id}/accept` > **[Accept many ownership recommendations](/api/rest/recommendations/accept-many-ownership-recommendations)** > > `POST /api/v1/recommendations/ownership/accept/batch` > **[Reject an ownership recommendation](/api/rest/recommendations/reject-an-ownership-recommendation)** > > `PUT /api/v1/recommendations/ownership/{id}/rejection` > **[Reject many ownership recommendations](/api/rest/recommendations/reject-many-ownership-recommendations)** > > `PUT /api/v1/recommendations/ownership/rejections/batch` > **[Restore an ownership recommendation](/api/rest/recommendations/restore-an-ownership-recommendation)** > > `DELETE /api/v1/recommendations/ownership/{id}/rejection` > **[Restore many ownership recommendations](/api/rest/recommendations/restore-many-ownership-recommendations)** > > `DELETE /api/v1/recommendations/ownership/rejections/batch` # Accept an ownership recommendation Source: https://docs.cortex.io/api/rest/recommendations/accept-an-ownership-recommendation /openapi/cortex_swagger.json post /api/v1/recommendations/ownership/{id}/accept Adds the recommended team as a direct owner of the entity, and records that the recommendation was accepted. When the entity's owners are managed in Git, a pull request adding the team is queued instead, and the result is PENDING until it merges. # Accept many ownership recommendations Source: https://docs.cortex.io/api/rest/recommendations/accept-many-ownership-recommendations /openapi/cortex_swagger.json post /api/v1/recommendations/ownership/accept/batch Accepts each recommendation as acceptOwnershipRecommendation does. Each one succeeds or fails on its own, and the results come back in request order. A GitOps pull request is queued (PENDING) only when every recommendation in the request is for the same entity; in a request spanning several entities, those whose owners are managed in Git fail with GITOPS_MANAGED. # List entities with ownership recommendations Source: https://docs.cortex.io/api/rest/recommendations/list-entities-with-ownership-recommendations /openapi/cortex_swagger.json get /api/v1/recommendations/ownership/entities One row for each entity that has ownership recommendations, with how many are open and the highest confidence among them, strongest first. # List ownership recommendations Source: https://docs.cortex.io/api/rest/recommendations/list-ownership-recommendations /openapi/cortex_swagger.json get /api/v1/recommendations/ownership Lists the team ownership recommendations you can see, strongest first. By default it lists open ones: not rejected, and the team does not already own the entity. Archived entities and teams never appear. # Reject an ownership recommendation Source: https://docs.cortex.io/api/rest/recommendations/reject-an-ownership-recommendation /openapi/cortex_swagger.json put /api/v1/recommendations/ownership/{id}/rejection Hides the recommendation from the open list. Owners do not change. Rejecting a recommendation that is already rejected does nothing. # Reject many ownership recommendations Source: https://docs.cortex.io/api/rest/recommendations/reject-many-ownership-recommendations /openapi/cortex_swagger.json put /api/v1/recommendations/ownership/rejections/batch Rejects each recommendation in the request. Each one succeeds or fails on its own, and the results come back in request order. Owners do not change. # Restore an ownership recommendation Source: https://docs.cortex.io/api/rest/recommendations/restore-an-ownership-recommendation /openapi/cortex_swagger.json delete /api/v1/recommendations/ownership/{id}/rejection Removes the rejection, or withdraws an accept still PENDING on a GitOps pull request, so the recommendation is open again. Owners do not change, and an open pull request is left as it is. Restoring an open recommendation does nothing. # Restore many ownership recommendations Source: https://docs.cortex.io/api/rest/recommendations/restore-many-ownership-recommendations /openapi/cortex_swagger.json delete /api/v1/recommendations/ownership/rejections/batch Removes the rejection, or withdraws a PENDING accept, from each recommendation in the request, as batchRejectOwnershipRecommendations does. Owners do not change. # Add a configuration Source: https://docs.cortex.io/api/rest/rollbar-api/add-a-configuration /openapi/cortex_swagger.json post /api/v1/rollbar/configuration # Delete a configuration Source: https://docs.cortex.io/api/rest/rollbar-api/delete-a-configuration /openapi/cortex_swagger.json delete /api/v1/rollbar/configurations # Retrieve a configuration Source: https://docs.cortex.io/api/rest/rollbar-api/retrieve-a-configuration /openapi/cortex_swagger.json get /api/v1/rollbar/default-configuration # Update the existing configuration Source: https://docs.cortex.io/api/rest/rollbar-api/update-the-existing-configuration /openapi/cortex_swagger.json put /api/v1/rollbar/configuration # Validate a configuration Source: https://docs.cortex.io/api/rest/rollbar-api/validate-a-configuration /openapi/cortex_swagger.json post /api/v1/rollbar/configuration/validate # Add a configuration Source: https://docs.cortex.io/api/rest/rootly-api/add-a-configuration /openapi/cortex_swagger.json post /api/v1/rootly/configuration # Delete a configuration by alias Source: https://docs.cortex.io/api/rest/rootly-api/delete-a-configuration-by-alias /openapi/cortex_swagger.json delete /api/v1/rootly/configuration/{alias} # Retrieve a configuration by alias Source: https://docs.cortex.io/api/rest/rootly-api/retrieve-a-configuration-by-alias /openapi/cortex_swagger.json get /api/v1/rootly/configuration/{alias} # Retrieve all configurations Source: https://docs.cortex.io/api/rest/rootly-api/retrieve-all-configurations /openapi/cortex_swagger.json get /api/v1/rootly/configurations # Retrieve default configuration Source: https://docs.cortex.io/api/rest/rootly-api/retrieve-default-configuration /openapi/cortex_swagger.json get /api/v1/rootly/default-configuration # Update a configuration Source: https://docs.cortex.io/api/rest/rootly-api/update-a-configuration /openapi/cortex_swagger.json put /api/v1/rootly/configuration/{alias} # Create or update Scaffolder template Source: https://docs.cortex.io/api/rest/scaffolder/create-or-update-scaffolder-template /openapi/cortex_swagger.json post /api/v1/scaffolders Create or update a Scaffolder template. API key must have the `Configure Scaffolder` permission. **Note:** If a Scaffolder template with the same tag already exists, it will be updated. # Delete Scaffolder template Source: https://docs.cortex.io/api/rest/scaffolder/delete-scaffolder-template /openapi/cortex_swagger.json delete /api/v1/scaffolders/{tagOrId} Delete a Scaffolder template by tag or Cortex ID. API key must have the `Configure Scaffolder` permission. # List Scaffolder templates Source: https://docs.cortex.io/api/rest/scaffolder/list-scaffolder-templates /openapi/cortex_swagger.json get /api/v1/scaffolders List Scaffolder templates. # Retrieve Scaffolder template Source: https://docs.cortex.io/api/rest/scaffolder/retrieve-scaffolder-template /openapi/cortex_swagger.json get /api/v1/scaffolders/{tagOrId} Retrieve a Scaffolder template by tag or Cortex ID. # Update Scaffolder template Source: https://docs.cortex.io/api/rest/scaffolder/update-scaffolder-template /openapi/cortex_swagger.json put /api/v1/scaffolders/{tagOrId} Update a Scaffolder template by tag or Cortex ID. API key must have the `Configure Scaffolder` permission. # Scaffolder Source: https://docs.cortex.io/api/rest/scaffolders Use these operations to interact with [Scaffolder templates](/streamline/workflows/scaffolder) in Cortex. ### Required permissions * List or retrieve Scaffolder templates: no additional permission is required. * Create, update, or delete Scaffolder templates: your API key must have the `Configure Scaffolder` permission. ### Identifying a template Every Scaffolder template has a `tag`: a stable, human-readable identifier that is unique within your workspace. Tags may contain lowercase letters, numbers, and dashes, and may not start or end with a dash. If you omit the tag when creating a template, Cortex derives one from the template's name. An existing template keeps its tag unless you supply a new one. Operations that take a `tagOrId` path parameter accept either the tag or the unique, auto-generated Cortex ID. Prefer the tag: it is the identifier you choose, so it stays readable and portable across workspaces. ### Creating and updating `POST /api/v1/scaffolders` is an upsert. If a template with the same tag already exists, that template is updated instead of a new one being created. Use `PUT /api/v1/scaffolders/{tagOrId}` when you want to update a specific template and have the request fail if it does not exist. ## Operations > **[List Scaffolder templates](/api/rest/scaffolder/list-scaffolder-templates)** > > `GET /api/v1/scaffolders` > **[Retrieve Scaffolder template](/api/rest/scaffolder/retrieve-scaffolder-template)** > > `GET /api/v1/scaffolders/{tagOrId}` > **[Create or update Scaffolder template](/api/rest/scaffolder/create-or-update-scaffolder-template)** > > `POST /api/v1/scaffolders` > **[Update Scaffolder template](/api/rest/scaffolder/update-scaffolder-template)** > > `PUT /api/v1/scaffolders/{tagOrId}` > **[Delete Scaffolder template](/api/rest/scaffolder/delete-scaffolder-template)** > > `DELETE /api/v1/scaffolders/{tagOrId}` # SCIM Source: https://docs.cortex.io/api/rest/scim Use these operations to interact with [SCIM-provisioned users](/configure/settings/managing-users/scim/okta-scim) in Cortex. ### Required permissions * Your API key must have the `Configure Open ID Connector & SCIM` permission. ### Required SCIM toggles Each operation is gated on the matching SCIM toggle in your [workspace settings](https://app.getcortexapp.com/settings/scim). A request whose required toggle is off is rejected without taking effect: | Operation | Required toggle | Response when the toggle is off | | - | - | - | | Create user (`POST /scim/v2/Users`) | Enable automatic provisioning of users | `403` | | Delete user (`DELETE /scim/v2/Users/{id}`) | Enable automatic deprovisioning of users | `403` | | Get user, Find users (`GET`) | Any SCIM toggle enabled | `403` | | Update or patch that deactivates a user (`active: false`) | Enable automatic deprovisioning of users | `400` | | Update or patch that reactivates a user (`active: true`) | Enable automatic provisioning of users | `400` | | Update or patch of other user attributes | Any SCIM toggle enabled | `400` | A user created or reactivated while automatic provisioning is enabled is always assigned your workspace's default role. ## Operations > [!NOTE] > > For the filter string in the `Find users` operation, use a value of `userName eq ""` to return a result based on an email value. > **[Find users](/api/rest/scim/find-users)** > > `GET /scim/v2/Users` > **[Gets a user by id](/api/rest/scim/gets-a-user-by-id)** > > `GET /scim/v2/Users/{id}` > **[Creates a user](/api/rest/scim/creates-a-user)** > > `POST /scim/v2/Users` > **[Updates a user](/api/rest/scim/updates-a-user)** > > `PUT /scim/v2/Users/{id}` > **[Patches a user](/api/rest/scim/patches-a-user)** > > `PATCH /scim/v2/Users/{id}` > **[Deletes a user](/api/rest/scim/deletes-a-user)** > > `DELETE /scim/v2/Users/{id}` # Creates a user Source: https://docs.cortex.io/api/rest/scim/creates-a-user /openapi/cortex_swagger.json post /scim/v2/Users Creates a user based on provided data. # Deletes a user Source: https://docs.cortex.io/api/rest/scim/deletes-a-user /openapi/cortex_swagger.json delete /scim/v2/Users/{id} Deletes a user based on provided id # Find users Source: https://docs.cortex.io/api/rest/scim/find-users /openapi/cortex_swagger.json get /scim/v2/Users Fetches users based on provided criteria # Gets a user by id Source: https://docs.cortex.io/api/rest/scim/gets-a-user-by-id /openapi/cortex_swagger.json get /scim/v2/Users/{id} Gets a user based on provided id # Patches a user Source: https://docs.cortex.io/api/rest/scim/patches-a-user /openapi/cortex_swagger.json patch /scim/v2/Users/{id} Replaces user details based on provided id and data # Updates a user Source: https://docs.cortex.io/api/rest/scim/updates-a-user /openapi/cortex_swagger.json put /scim/v2/Users/{id} Updates a user based on provided id and data # Scorecards Source: https://docs.cortex.io/api/rest/scorecards Use these operations to interact with [Scorecards](/standardize/scorecards) in Cortex. ### Required permissions * Create, read, update, or delete Scorecards: Your API key must have the `Edit Scorecards` permission. * View Scorecards: Your API key must have the `View Scorecards` permission. * Approve or revoke Scorecard exemptions: Your API key must have the `Configure Scorecard exemptions` permission. * List Scorecard exemptions: API keys with the `View Scorecard Exemptions` permission see every exemption. A personal API key without that permission sees only exemptions its user requested in the Cortex UI; exemptions requested through the API are attributed to the API key, not the user. ## Operations > **[List Scorecards](/api/rest/scorecards/list-scorecards)** > > `GET /api/v1/scorecards` > **[List Scorecard rule exemptions](/api/rest/scorecards/list-scorecard-rule-exemptions)** > > `GET /api/v1/scorecards/exemptions` > **[Retrieve Scorecard scores](/api/rest/scorecards/retrieve-scorecard-scores)** > > `GET /api/v1/scorecards/{tag}/scores` > **[Retrieve entity Scorecard scores](/api/rest/catalog-entities/retrieve-entity-scorecard-scores)** > > `GET /api/v1/catalog/{tagOrId}/scorecards` > **[Retrieve Scorecard](/api/rest/scorecards/retrieve-scorecard)** > > `GET /api/v1/scorecards/{tag}` > **[Retrieve Scorecard descriptor](/api/rest/scorecards/retrieve-scorecard-descriptor)** > > `GET /api/v1/scorecards/{tag}/descriptor` > **[Retrieve Scorecard shields.io badge](/api/rest/scorecards/retrieve-scorecard-shieldsio-badge)** > > `GET /api/v1/scorecards/{scorecardTag}/entity/{tagOrId}/badge` > **[Retrieve next steps for entity in Scorecard](/api/rest/scorecards/retrieve-next-steps-for-entity-in-scorecard)** > > `GET /api/v1/scorecards/{tag}/next-steps` > **[Create or update Scorecard](/api/rest/scorecards/create-or-update-scorecard)** > > `POST /api/v1/scorecards/descriptor` > **[Request Scorecard rule exemption](/api/rest/scorecards/request-scorecard-rule-exemption)** > > `POST /api/v1/scorecards/{tag}/entity/{entityTag}/exemption` > **[Evaluate entity scorecard score](/api/rest/scorecards/evaluate-entity-scorecard-score)** > > `POST /api/v1/scorecards/{tag}/entity/{entityTag}/scores` > **[Revoke Scorecard rule exemption](/api/rest/scorecards/revoke-scorecard-rule-exemption)** > > `PUT /api/v1/scorecards/{tag}/entity/{entityTag}/exemption/revoke` > **[Approve Scorecard rule exemption](/api/rest/scorecards/approve-scorecard-rule-exemption)** > > `PUT /api/v1/scorecards/{tag}/entity/{entityTag}/exemption/approve` > **[Deny Scorecard rule exemption](/api/rest/scorecards/deny-scorecard-rule-exemption)** > > `PUT /api/v1/scorecards/{tag}/entity/{entityTag}/exemption/deny` > **[Delete Scorecard](/api/rest/scorecards/delete-scorecard)** > > `DELETE /api/v1/scorecards/{tag}` # Approve Scorecard rule exemption Source: https://docs.cortex.io/api/rest/scorecards/approve-scorecard-rule-exemption /openapi/cortex_swagger.json put /api/v1/scorecards/{tag}/entity/{entityTag}/exemption/approve Approve Scorecard rule exemption # Create or update Scorecard Source: https://docs.cortex.io/api/rest/scorecards/create-or-update-scorecard /openapi/cortex_swagger.json post /api/v1/scorecards/descriptor Create or update a Scorecard using the descriptor YAML. The operation is determined by the existence of a Scorecard with the same `tag` as passed in the descriptor. # Delete Scorecard Source: https://docs.cortex.io/api/rest/scorecards/delete-scorecard /openapi/cortex_swagger.json delete /api/v1/scorecards/{tag} # Deny Scorecard rule exemption Source: https://docs.cortex.io/api/rest/scorecards/deny-scorecard-rule-exemption /openapi/cortex_swagger.json put /api/v1/scorecards/{tag}/entity/{entityTag}/exemption/deny Deny Scorecard rule exemption # Evaluate entity scorecard score Source: https://docs.cortex.io/api/rest/scorecards/evaluate-entity-scorecard-score /openapi/cortex_swagger.json post /api/v1/scorecards/{tag}/entity/{entityTag}/scores Triggers score evaluation for entity scorecard # List Scorecard rule exemptions Source: https://docs.cortex.io/api/rest/scorecards/list-scorecard-rule-exemptions /openapi/cortex_swagger.json get /api/v1/scorecards/exemptions List rule exemptions across Scorecards, newest first. Callers with permission to view Scorecard exemptions see every exemption; other users see only the exemptions they requested. # List Scorecards Source: https://docs.cortex.io/api/rest/scorecards/list-scorecards /openapi/cortex_swagger.json get /api/v1/scorecards Returns scorecards matching optional search criteria. If search criteria is specified we will use search logic, which will not find Scorecards that have yet to be evaluated # Request Scorecard rule exemption Source: https://docs.cortex.io/api/rest/scorecards/request-scorecard-rule-exemption /openapi/cortex_swagger.json post /api/v1/scorecards/{tag}/entity/{entityTag}/exemption Request Scorecard rule exemption # Retrieve next steps for entity in Scorecard Source: https://docs.cortex.io/api/rest/scorecards/retrieve-next-steps-for-entity-in-scorecard /openapi/cortex_swagger.json get /api/v1/scorecards/{tag}/next-steps # Retrieve Scorecard Source: https://docs.cortex.io/api/rest/scorecards/retrieve-scorecard /openapi/cortex_swagger.json get /api/v1/scorecards/{tag} # Retrieve Scorecard descriptor Source: https://docs.cortex.io/api/rest/scorecards/retrieve-scorecard-descriptor /openapi/cortex_swagger.json get /api/v1/scorecards/{tag}/descriptor # Retrieve Scorecard scores Source: https://docs.cortex.io/api/rest/scorecards/retrieve-scorecard-scores /openapi/cortex_swagger.json get /api/v1/scorecards/{tag}/scores Returns latest scores for all entities in the Scorecard # Retrieve Scorecard shields.io badge Source: https://docs.cortex.io/api/rest/scorecards/retrieve-scorecard-shieldsio-badge /openapi/cortex_swagger.json get /api/v1/scorecards/{scorecardTag}/entity/{tagOrId}/badge # Revoke Scorecard rule exemption Source: https://docs.cortex.io/api/rest/scorecards/revoke-scorecard-rule-exemption /openapi/cortex_swagger.json put /api/v1/scorecards/{tag}/entity/{entityTag}/exemption/revoke Revoke Scorecard rule exemption # Secrets Source: https://docs.cortex.io/api/rest/secrets Use these operations to interact with [secrets](/configure/settings/api-keys/secrets) in Cortex. ### Required permissions * Your API key must have the `Create secrets` permission. > **[List secrets](/api/rest/secrets/list-secrets)** > > `GET /api/v1/secrets` > **[Retrieve secret](/api/rest/secrets/retrieve-secret)** > > `GET /api/v1/secrets/{tagOrId}` > **[Create secret](/api/rest/secrets/create-secret)** > > `POST /api/v1/secrets` > **[Update secret](/api/rest/secrets/update-secret)** > > `PUT /api/v1/secrets/{tagOrId}` > **[Delete secret](/api/rest/secrets/delete-secret)** > > `DELETE /api/v1/secrets/{tagOrId}` # Create secret Source: https://docs.cortex.io/api/rest/secrets/create-secret /openapi/cortex_swagger.json post /api/v1/secrets API key must have the `Create secrets` permission. # Delete secret Source: https://docs.cortex.io/api/rest/secrets/delete-secret /openapi/cortex_swagger.json delete /api/v1/secrets/{tagOrId} API key must have the `Create secrets` permission. # List secrets Source: https://docs.cortex.io/api/rest/secrets/list-secrets /openapi/cortex_swagger.json get /api/v1/secrets API key must have the `Create secrets` permission. # Retrieve secret Source: https://docs.cortex.io/api/rest/secrets/retrieve-secret /openapi/cortex_swagger.json get /api/v1/secrets/{tagOrId} API key must have the `Create secrets` permission. # Update secret Source: https://docs.cortex.io/api/rest/secrets/update-secret /openapi/cortex_swagger.json put /api/v1/secrets/{tagOrId} API key must have the `Create secrets` permission. # Add a single configuration Source: https://docs.cortex.io/api/rest/semgrep-api/add-a-single-configuration /openapi/cortex_swagger.json post /api/v1/semgrep/configuration # Add multiple configurations Source: https://docs.cortex.io/api/rest/semgrep-api/add-multiple-configurations /openapi/cortex_swagger.json post /api/v1/semgrep/configurations # Delete a configuration Source: https://docs.cortex.io/api/rest/semgrep-api/delete-a-configuration /openapi/cortex_swagger.json delete /api/v1/semgrep/configuration/{alias} # Delete all configurations Source: https://docs.cortex.io/api/rest/semgrep-api/delete-all-configurations /openapi/cortex_swagger.json delete /api/v1/semgrep/configurations # Retrieve a configuration Source: https://docs.cortex.io/api/rest/semgrep-api/retrieve-a-configuration /openapi/cortex_swagger.json get /api/v1/semgrep/configuration/{alias} # Retrieve configurations Source: https://docs.cortex.io/api/rest/semgrep-api/retrieve-configurations /openapi/cortex_swagger.json get /api/v1/semgrep/configurations # Retrieve default configuration Source: https://docs.cortex.io/api/rest/semgrep-api/retrieve-default-configuration /openapi/cortex_swagger.json get /api/v1/semgrep/default-configuration # Update a configuration Source: https://docs.cortex.io/api/rest/semgrep-api/update-a-configuration /openapi/cortex_swagger.json put /api/v1/semgrep/configuration/{alias} WARNING: Updating aliases for configurations or changing the default configuration could cause entity YAMLs that use this integration to break. # Validate a configuration Source: https://docs.cortex.io/api/rest/semgrep-api/validate-a-configuration /openapi/cortex_swagger.json post /api/v1/semgrep/configuration/validate/{alias} # Validate all configurations Source: https://docs.cortex.io/api/rest/semgrep-api/validate-all-configurations /openapi/cortex_swagger.json post /api/v1/semgrep/configuration/validate # Add a configuration Source: https://docs.cortex.io/api/rest/sentry-api/add-a-configuration /openapi/cortex_swagger.json post /api/v1/sentry/configuration # Delete a configuration Source: https://docs.cortex.io/api/rest/sentry-api/delete-a-configuration /openapi/cortex_swagger.json delete /api/v1/sentry/configurations # Retrieve a configuration Source: https://docs.cortex.io/api/rest/sentry-api/retrieve-a-configuration /openapi/cortex_swagger.json get /api/v1/sentry/default-configuration # Update the existing configuration Source: https://docs.cortex.io/api/rest/sentry-api/update-the-existing-configuration /openapi/cortex_swagger.json put /api/v1/sentry/configuration # Validate a configuration Source: https://docs.cortex.io/api/rest/sentry-api/validate-a-configuration /openapi/cortex_swagger.json post /api/v1/sentry/configuration/validate # Add a configuration Source: https://docs.cortex.io/api/rest/servicenow-api/add-a-configuration /openapi/cortex_swagger.json post /api/v1/servicenow/configuration # Delete a configuration Source: https://docs.cortex.io/api/rest/servicenow-api/delete-a-configuration /openapi/cortex_swagger.json delete /api/v1/servicenow/configurations # Retrieve a configuration Source: https://docs.cortex.io/api/rest/servicenow-api/retrieve-a-configuration /openapi/cortex_swagger.json get /api/v1/servicenow/default-configuration # Update the existing configuration Source: https://docs.cortex.io/api/rest/servicenow-api/update-the-existing-configuration /openapi/cortex_swagger.json put /api/v1/servicenow/configuration # Validate a configuration Source: https://docs.cortex.io/api/rest/servicenow-api/validate-a-configuration /openapi/cortex_swagger.json post /api/v1/servicenow/configuration/validate # Add a configuration Source: https://docs.cortex.io/api/rest/servicenow-cloud-observability-api/add-a-configuration /openapi/cortex_swagger.json post /api/v1/lightstep/configuration # Delete a configuration Source: https://docs.cortex.io/api/rest/servicenow-cloud-observability-api/delete-a-configuration /openapi/cortex_swagger.json delete /api/v1/lightstep/configurations # Retrieve a configuration Source: https://docs.cortex.io/api/rest/servicenow-cloud-observability-api/retrieve-a-configuration /openapi/cortex_swagger.json get /api/v1/lightstep/default-configuration # Update the existing configuration Source: https://docs.cortex.io/api/rest/servicenow-cloud-observability-api/update-the-existing-configuration /openapi/cortex_swagger.json put /api/v1/lightstep/configuration # Validate a configuration Source: https://docs.cortex.io/api/rest/servicenow-cloud-observability-api/validate-a-configuration /openapi/cortex_swagger.json post /api/v1/lightstep/configuration/validate # Add a configuration Source: https://docs.cortex.io/api/rest/snyk-api/add-a-configuration /openapi/cortex_swagger.json post /api/v1/snyk/configuration # Delete a configuration Source: https://docs.cortex.io/api/rest/snyk-api/delete-a-configuration /openapi/cortex_swagger.json delete /api/v1/snyk/configurations # Retrieve a configuration Source: https://docs.cortex.io/api/rest/snyk-api/retrieve-a-configuration /openapi/cortex_swagger.json get /api/v1/snyk/default-configuration # Update the existing configuration Source: https://docs.cortex.io/api/rest/snyk-api/update-the-existing-configuration /openapi/cortex_swagger.json put /api/v1/snyk/configuration # Validate a configuration Source: https://docs.cortex.io/api/rest/snyk-api/validate-a-configuration /openapi/cortex_swagger.json post /api/v1/snyk/configuration/validate # Add a single configuration Source: https://docs.cortex.io/api/rest/sonarqube-api/add-a-single-configuration /openapi/cortex_swagger.json post /api/v1/sonarqube/configuration # Add multiple configurations Source: https://docs.cortex.io/api/rest/sonarqube-api/add-multiple-configurations /openapi/cortex_swagger.json post /api/v1/sonarqube/configurations # Delete a configuration Source: https://docs.cortex.io/api/rest/sonarqube-api/delete-a-configuration /openapi/cortex_swagger.json delete /api/v1/sonarqube/configuration/{alias} # Delete all configurations Source: https://docs.cortex.io/api/rest/sonarqube-api/delete-all-configurations /openapi/cortex_swagger.json delete /api/v1/sonarqube/configurations # Retrieve a configuration Source: https://docs.cortex.io/api/rest/sonarqube-api/retrieve-a-configuration /openapi/cortex_swagger.json get /api/v1/sonarqube/configuration/{alias} # Retrieve configurations Source: https://docs.cortex.io/api/rest/sonarqube-api/retrieve-configurations /openapi/cortex_swagger.json get /api/v1/sonarqube/configurations # Retrieve default configuration Source: https://docs.cortex.io/api/rest/sonarqube-api/retrieve-default-configuration /openapi/cortex_swagger.json get /api/v1/sonarqube/default-configuration # Update a configuration Source: https://docs.cortex.io/api/rest/sonarqube-api/update-a-configuration /openapi/cortex_swagger.json put /api/v1/sonarqube/configuration/{alias} WARNING: Updating aliases for configurations or changing the default configuration could cause entity YAMLs that use this integration to break. # Validate a configuration Source: https://docs.cortex.io/api/rest/sonarqube-api/validate-a-configuration /openapi/cortex_swagger.json post /api/v1/sonarqube/configuration/validate/{alias} # Validate all configurations Source: https://docs.cortex.io/api/rest/sonarqube-api/validate-all-configurations /openapi/cortex_swagger.json post /api/v1/sonarqube/configuration/validate # Add a configuration Source: https://docs.cortex.io/api/rest/splunk-observability-cloud-api/add-a-configuration /openapi/cortex_swagger.json post /api/v1/signalfx/configuration # Delete a configuration Source: https://docs.cortex.io/api/rest/splunk-observability-cloud-api/delete-a-configuration /openapi/cortex_swagger.json delete /api/v1/signalfx/configurations # Retrieve a configuration Source: https://docs.cortex.io/api/rest/splunk-observability-cloud-api/retrieve-a-configuration /openapi/cortex_swagger.json get /api/v1/signalfx/default-configuration # Update the existing configuration Source: https://docs.cortex.io/api/rest/splunk-observability-cloud-api/update-the-existing-configuration /openapi/cortex_swagger.json put /api/v1/signalfx/configuration # Validate a configuration Source: https://docs.cortex.io/api/rest/splunk-observability-cloud-api/validate-a-configuration /openapi/cortex_swagger.json post /api/v1/signalfx/configuration/validate # Add a configuration Source: https://docs.cortex.io/api/rest/splunk-on-call-api/add-a-configuration /openapi/cortex_swagger.json post /api/v1/victorops/configuration # Delete a configuration Source: https://docs.cortex.io/api/rest/splunk-on-call-api/delete-a-configuration /openapi/cortex_swagger.json delete /api/v1/victorops/configurations # Retrieve a configuration Source: https://docs.cortex.io/api/rest/splunk-on-call-api/retrieve-a-configuration /openapi/cortex_swagger.json get /api/v1/victorops/default-configuration # Update the existing configuration Source: https://docs.cortex.io/api/rest/splunk-on-call-api/update-the-existing-configuration /openapi/cortex_swagger.json put /api/v1/victorops/configuration # Validate a configuration Source: https://docs.cortex.io/api/rest/splunk-on-call-api/validate-a-configuration /openapi/cortex_swagger.json post /api/v1/victorops/configuration/validate # Add a configuration Source: https://docs.cortex.io/api/rest/sumo-logic-api/add-a-configuration /openapi/cortex_swagger.json post /api/v1/sumologic/configuration # Delete a configuration Source: https://docs.cortex.io/api/rest/sumo-logic-api/delete-a-configuration /openapi/cortex_swagger.json delete /api/v1/sumologic/configurations # Retrieve a configuration Source: https://docs.cortex.io/api/rest/sumo-logic-api/retrieve-a-configuration /openapi/cortex_swagger.json get /api/v1/sumologic/default-configuration # Update the existing configuration Source: https://docs.cortex.io/api/rest/sumo-logic-api/update-the-existing-configuration /openapi/cortex_swagger.json put /api/v1/sumologic/configuration # Validate a configuration Source: https://docs.cortex.io/api/rest/sumo-logic-api/validate-a-configuration /openapi/cortex_swagger.json post /api/v1/sumologic/configuration/validate # Team Hierarchies Source: https://docs.cortex.io/api/rest/team-hierarchies Use these operations to interact with [team hierarchies](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/teams#understanding-hierarchies) in Cortex. ### Required permissions Your API key must have the `Edit entities` permission. ## Operations > **[Retrieve team relationships](/api/rest/team-hierarchies/retrieve-team-relationships)** > > `GET /api/v1/teams/relationships` > **[Replace all relationships](/api/rest/team-hierarchies/replace-all-relationships)** > > `PUT /api/v1/teams/relationships` # Replace all relationships Source: https://docs.cortex.io/api/rest/team-hierarchies/replace-all-relationships /openapi/cortex_swagger.json put /api/v1/teams/relationships # Retrieve team relationships Source: https://docs.cortex.io/api/rest/team-hierarchies/retrieve-team-relationships /openapi/cortex_swagger.json get /api/v1/teams/relationships # Teams Source: https://docs.cortex.io/api/rest/teams Use these operations to interact with [teams](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/teams) in Cortex. This page lists operations specific to team entities. See [Catalog entities](/api/rest/catalog-entities) for API operations relating to all entity types (including teams). ### Required permissions Your API key must have the `Edit entities` permission. ## Operations > **[Retrieve list of teams or team details](/api/rest/teams/retrieve-list-of-teams-or-team-details)** > > `GET /api/v1/teams` > **[Retrieve team details](/api/rest/teams/retrieve-team-details)** > > `GET /api/v1/teams/{tagOrId}` > **[Create a team](/api/rest/teams/create-a-team)** > > `POST /api/v1/teams` > **[\[Cortex managed teams\] Update members in team](/api/rest/teams/\[cortex-managed-teams]-update-members-in-team)** > > `PUT /api/v1/teams/{tagOrId}/members` > **[\[Cortex managed teams\] Update members in team](/api/rest/teams-advanced/\[cortex-managed-teams]-update-members-in-team)** > > `PUT /api/v1/teams/members` > **[Update team metadata](/api/rest/teams-advanced/update-team-metadata)** > > `PUT /api/v1/teams` > **[Update team metadata](/api/rest/teams/update-team-metadata)** > > `PUT /api/v1/teams/{tagOrId}` > **[Archive team](/api/rest/teams/archive-team)** > > `PUT /api/v1/teams/{tagOrId}/archive` > **[Unarchive team](/api/rest/teams/unarchive-team)** > > `PUT /api/v1/teams/{tagOrId}/unarchive` > **[Delete team](/api/rest/teams/delete-team)** > > `DELETE /api/v1/teams` > **[Delete team by tag or ID](/api/rest/teams/delete-team-by-tag-or-id)** > > `DELETE /api/v1/teams/{tagOrId}` # [Cortex managed teams] Update members in team Source: https://docs.cortex.io/api/rest/teams-advanced/[cortex-managed-teams]-update-members-in-team /openapi/cortex_swagger.json put /api/v1/teams/members For teams whose members are not backed by an IdP, use this API to update the team members. Note that it will replace the members in the team with the members defined in this request. *Warning:* This API should only be used if your team identifier contains non-alphanumeric characters. Otherwise, use the standard API under `Teams`. # Update team metadata Source: https://docs.cortex.io/api/rest/teams-advanced/update-team-metadata /openapi/cortex_swagger.json put /api/v1/teams *Warning:* This API should only be used if your team identifier contains non-alphanumeric characters. Otherwise, use the standard API under `Teams`. # [Cortex managed teams] Update members in team Source: https://docs.cortex.io/api/rest/teams/[cortex-managed-teams]-update-members-in-team /openapi/cortex_swagger.json put /api/v1/teams/{tagOrId}/members For teams whose members are not backed by an IdP, use this API to update the team members. Note that it will replace the members in the team with the members defined in this request. # Archive team Source: https://docs.cortex.io/api/rest/teams/archive-team /openapi/cortex_swagger.json put /api/v1/teams/{tagOrId}/archive # Create a team Source: https://docs.cortex.io/api/rest/teams/create-a-team /openapi/cortex_swagger.json post /api/v1/teams Team memberships can be backed by an IdP group (from Okta, Azure AD, Google Groups, etc), or can be managed directly through Cortex. Each has a separate request shape, so make sure to select the correct example. # Delete team Source: https://docs.cortex.io/api/rest/teams/delete-team /openapi/cortex_swagger.json delete /api/v1/teams # Delete team by tag or ID Source: https://docs.cortex.io/api/rest/teams/delete-team-by-tag-or-id /openapi/cortex_swagger.json delete /api/v1/teams/{tagOrId} # Retrieve list of teams or team details Source: https://docs.cortex.io/api/rest/teams/retrieve-list-of-teams-or-team-details /openapi/cortex_swagger.json get /api/v1/teams *Warning:* This API can return team details if you pass in a teamTag query parameter. However, this should only be used to retrieve team details if your team identifier contains non-alphanumeric characters. Otherwise, use the standard API under `Teams` -> `Retrieve team details`. When retrieving team details, the response will be a single team entity instead of a list. Note: the response objects can also include an `idpGroup` or `cortexTeam` field depending on whether the team contains a `group` or only consists of individually defined `members`. # Retrieve team details Source: https://docs.cortex.io/api/rest/teams/retrieve-team-details /openapi/cortex_swagger.json get /api/v1/teams/{tagOrId} # Unarchive team Source: https://docs.cortex.io/api/rest/teams/unarchive-team /openapi/cortex_swagger.json put /api/v1/teams/{tagOrId}/unarchive # Update team metadata Source: https://docs.cortex.io/api/rest/teams/update-team-metadata /openapi/cortex_swagger.json put /api/v1/teams/{tagOrId} # Users Source: https://docs.cortex.io/api/rest/users Use these operations to list users in your Cortex workspace along with their profile metadata, and to retrieve their role assignments. ### Required permissions Your API token must have the `View Roles` permission. > [!NOTE] > > Some built-in API key roles (`VIWER`, `USER`, and `MANAGER`) do not include `View Roles`. To call this endpoint with an API key, use an `ADMIN` key or create a new one and assign it a [custom role](/configure/settings/managing-users/permissioning/custom-roles) that grants `View Roles`. ## Operations > **[List users](/api/rest/users/list-users)** > > `GET /api/v1/users` > **[List user role assignments](/api/rest/users/list-user-role-assignments)** > > `GET /api/v1/users/roles` # List user role assignments Source: https://docs.cortex.io/api/rest/users/list-user-role-assignments /openapi/cortex_swagger.json get /api/v1/users/roles Returns the role assignments for every user in your Cortex tenant, intended for access reviews and access governance reporting. Each entry lists the user along with their assigned built-in (BASIC) and CUSTOM roles. Requires the View Roles permission; assign it to a custom role to issue a least-privilege API key for automated reporting. # List users Source: https://docs.cortex.io/api/rest/users/list-users /openapi/cortex_swagger.json get /api/v1/users Returns every user in your Cortex tenant along with their profile metadata: name, email, join date, and last active timestamp. Intended for access reviews, compliance, and auditing. Role assignments are available from the separate GET /api/v1/users/roles endpoint. Requires the View Roles permission; assign it to a custom role to issue a least-privilege API key for automated reporting. # Add a configuration Source: https://docs.cortex.io/api/rest/veracode-api/add-a-configuration /openapi/cortex_swagger.json post /api/v1/veracode/configuration # Delete a configuration Source: https://docs.cortex.io/api/rest/veracode-api/delete-a-configuration /openapi/cortex_swagger.json delete /api/v1/veracode/configurations # Retrieve a configuration Source: https://docs.cortex.io/api/rest/veracode-api/retrieve-a-configuration /openapi/cortex_swagger.json get /api/v1/veracode/default-configuration # Update the existing configuration Source: https://docs.cortex.io/api/rest/veracode-api/update-the-existing-configuration /openapi/cortex_swagger.json put /api/v1/veracode/configuration # Validate a configuration Source: https://docs.cortex.io/api/rest/veracode-api/validate-a-configuration /openapi/cortex_swagger.json post /api/v1/veracode/configuration/validate # Verifications Source: https://docs.cortex.io/api/rest/verifications Use these operations to manage [data verification](/configure/settings/entity-settings/verification) in Cortex. A verification period asks entity owners to confirm that their entities' information is accurate. To see or answer verifications for a single entity, use the verification operations under [Catalog Entities](/api/rest/catalog-entities). ### Required permissions Your API key must have the `Configure Verification Periods` permission. To answer verifications for entities you don't own, your API key must have the `Verify any entity` permission. ## Operations > **[Retrieve verification periods](/api/rest/verifications/retrieve-verification-periods)** > > `GET /api/v1/verification-periods` > **[Create a verification period](/api/rest/verifications/create-a-verification-period)** > > `POST /api/v1/verification-periods` > **[Retrieve a verification period](/api/rest/verifications/retrieve-a-verification-period)** > > `GET /api/v1/verification-periods/{periodCid}` > **[Update a verification period](/api/rest/verifications/update-a-verification-period)** > > `PUT /api/v1/verification-periods/{periodCid}` > **[Delete a verification period](/api/rest/verifications/delete-a-verification-period)** > > `DELETE /api/v1/verification-periods/{periodCid}` > **[Retrieve verifications](/api/rest/verifications/retrieve-verifications)** > > `GET /api/v1/verifications` > **[Verify entities in bulk](/api/rest/verifications/verify-entities-in-bulk)** > > `PUT /api/v1/verifications` # Create a verification period Source: https://docs.cortex.io/api/rest/verifications/create-a-verification-period /openapi/cortex_swagger.json post /api/v1/verification-periods Opens a verification campaign over the entities its scope selects. Every selected entity gets a PENDING verification immediately, except under a cqlQuery scope, which is evaluated in the background, so the counts read zero until it finishes. # Delete a verification period Source: https://docs.cortex.io/api/rest/verifications/delete-a-verification-period /openapi/cortex_swagger.json delete /api/v1/verification-periods/{periodCid} Closes the period and stops it appearing in reads, along with the verifications recorded against it. The CID is not reissued, so the period cannot be restored through this API. # Retrieve a verification period Source: https://docs.cortex.io/api/rest/verifications/retrieve-a-verification-period /openapi/cortex_swagger.json get /api/v1/verification-periods/{periodCid} # Retrieve verification periods Source: https://docs.cortex.io/api/rest/verifications/retrieve-verification-periods /openapi/cortex_swagger.json get /api/v1/verification-periods Returns every verification period in the workspace, open or closed, with a count of how many entities are outstanding. # Retrieve verifications Source: https://docs.cortex.io/api/rest/verifications/retrieve-verifications /openapi/cortex_swagger.json get /api/v1/verifications Returns every verification in the workspace, one entry per entity and verification period, including entities that have not been verified yet. Each entry names the entity it belongs to, and who verified it once someone has. # Update a verification period Source: https://docs.cortex.io/api/rest/verifications/update-a-verification-period /openapi/cortex_swagger.json put /api/v1/verification-periods/{periodCid} Replaces the period in full; omitted optional fields are cleared rather than left alone. Changing the scope changes who owes a verification: widening it adds PENDING entries, and narrowing it removes entries along with any answer already recorded for them. # Verify entities in bulk Source: https://docs.cortex.io/api/rest/verifications/verify-entities-in-bulk /openapi/cortex_swagger.json put /api/v1/verifications Answers many entity-and-period pairs in one call. Each entry is answered on its own merits: an entity the caller may not verify is returned under `errors` while the rest are still recorded, because eligibility depends on who owns each entity. Read `errors` on every response -- a 200 does not mean every entry was recorded. # Add a configuration Source: https://docs.cortex.io/api/rest/wiz-api/add-a-configuration /openapi/cortex_swagger.json post /api/v1/wiz/configuration # Delete a configuration Source: https://docs.cortex.io/api/rest/wiz-api/delete-a-configuration /openapi/cortex_swagger.json delete /api/v1/wiz/configurations # Retrieve a configuration Source: https://docs.cortex.io/api/rest/wiz-api/retrieve-a-configuration /openapi/cortex_swagger.json get /api/v1/wiz/default-configuration # Update the existing configuration Source: https://docs.cortex.io/api/rest/wiz-api/update-the-existing-configuration /openapi/cortex_swagger.json put /api/v1/wiz/configuration # Validate a configuration Source: https://docs.cortex.io/api/rest/wiz-api/validate-a-configuration /openapi/cortex_swagger.json post /api/v1/wiz/configuration/validate # Add a configuration Source: https://docs.cortex.io/api/rest/workday-api/add-a-configuration /openapi/cortex_swagger.json post /api/v1/workday/configuration # Delete a configuration Source: https://docs.cortex.io/api/rest/workday-api/delete-a-configuration /openapi/cortex_swagger.json delete /api/v1/workday/configurations # Retrieve a configuration Source: https://docs.cortex.io/api/rest/workday-api/retrieve-a-configuration /openapi/cortex_swagger.json get /api/v1/workday/default-configuration # Update the existing configuration Source: https://docs.cortex.io/api/rest/workday-api/update-the-existing-configuration /openapi/cortex_swagger.json put /api/v1/workday/configuration # Validate a configuration Source: https://docs.cortex.io/api/rest/workday-api/validate-a-configuration /openapi/cortex_swagger.json post /api/v1/workday/configuration/validate # Workflows Source: https://docs.cortex.io/api/rest/workflows Use these operations to interact with [Workflows](/streamline/workflows) in Cortex. ### Required permissions * View Workflows: Your API key must have the `View Workflows` permission. * Create or update Workflows: Your API key must have the `Edit Workflows` permission. * Callback a paused async HTTP block: Your API key must have the `Execute Workflow Runs` permission. * Run a workflow: Your API key must have the `Execute Workflow Runs` permission. * View or list workflow runs: Your API key must have the `View workflow runs` permission. ## Operations > **[List workflows](/api/rest/workflows/list-workflows)** > > `GET /api/v1/workflows` > **[Retrieve workflow](/api/rest/workflows/retrieve-workflow)** > > `GET /api/v1/workflows/{tagOrId}` > **[Create or update workflow](/api/rest/workflows/create-or-update-workflow)** > > `POST /api/v1/workflows` > **[Validates YAML descriptor](/api/rest/workflows/validates-yaml-descriptor)** > > `POST /api/v1/workflows/validate` > **[Update asynchronous HTTP request Workflow block](/api/rest/workflows/update-asynchronous-http-request-workflow-block)** > > `POST /api/v1/workflows/{tagOrId}/callback/{callbackId}` > **[Delete workflow](/api/rest/workflows/delete-workflow)** > > `DELETE /api/v1/workflows/{tagOrId}` > **[Run a workflow](/api/rest/workflows/run-a-workflow)** > > `POST /api/v1/workflows/{tagOrId}/runs` > **[Get workflow run details](/api/rest/workflows/get-workflow-run-details)** > > `GET /api/v1/workflows/{tagOrId}/runs/{runId}` > **[List workflow runs](/api/rest/workflows/list-workflow-runs)** > > `GET /api/v1/workflows/runs` # Create or update workflow Source: https://docs.cortex.io/api/rest/workflows/create-or-update-workflow /openapi/cortex_swagger.json post /api/v1/workflows Create or update new workflow. API key must have the `Edit workflows` permission. **Note:** If a workflow with the same tag already exists, it will be updated. # Delete workflow Source: https://docs.cortex.io/api/rest/workflows/delete-workflow /openapi/cortex_swagger.json delete /api/v1/workflows/{tagOrId} Delete workflow by tag or ID. API key must have the `Edit workflows` permission. # Get workflow run details Source: https://docs.cortex.io/api/rest/workflows/get-workflow-run-details /openapi/cortex_swagger.json get /api/v1/workflows/{tagOrId}/runs/{runId} Retrieve details of a specific workflow run. API key must have the `View workflow runs` permission. # List workflow runs Source: https://docs.cortex.io/api/rest/workflows/list-workflow-runs /openapi/cortex_swagger.json get /api/v1/workflows/runs List workflow runs based on filters. API key must have the `View workflow runs` permission. # List workflows Source: https://docs.cortex.io/api/rest/workflows/list-workflows /openapi/cortex_swagger.json get /api/v1/workflows List workflows. API key must have the `View workflows` permission. # Retrieve workflow Source: https://docs.cortex.io/api/rest/workflows/retrieve-workflow /openapi/cortex_swagger.json get /api/v1/workflows/{tagOrId} Retrieve workflow by tag or ID. API key must have the `View workflows` permission. # Run a workflow Source: https://docs.cortex.io/api/rest/workflows/run-a-workflow /openapi/cortex_swagger.json post /api/v1/workflows/{tagOrId}/runs Start a new run for a workflow. API key must have the `Run workflows` permission and the workflow must be runnable via API # Update asynchronous HTTP request Workflow block Source: https://docs.cortex.io/api/rest/workflows/update-asynchronous-http-request-workflow-block /openapi/cortex_swagger.json post /api/v1/workflows/{tagOrId}/callback/{callbackId} Updates an asynchronous HTTP request Workflow block. API key must have the `Edit workflow runs` permission. # Validates YAML descriptor Source: https://docs.cortex.io/api/rest/workflows/validates-yaml-descriptor /openapi/cortex_swagger.json post /api/v1/workflows/validate Validates YAML descriptor. # Add a configuration Source: https://docs.cortex.io/api/rest/xmatters-api/add-a-configuration /openapi/cortex_swagger.json post /api/v1/xmatters/configuration # Delete a configuration Source: https://docs.cortex.io/api/rest/xmatters-api/delete-a-configuration /openapi/cortex_swagger.json delete /api/v1/xmatters/configurations # Retrieve a configuration Source: https://docs.cortex.io/api/rest/xmatters-api/retrieve-a-configuration /openapi/cortex_swagger.json get /api/v1/xmatters/default-configuration # Update the existing configuration Source: https://docs.cortex.io/api/rest/xmatters-api/update-the-existing-configuration /openapi/cortex_swagger.json put /api/v1/xmatters/configuration # Validate a configuration Source: https://docs.cortex.io/api/rest/xmatters-api/validate-a-configuration /openapi/cortex_swagger.json post /api/v1/xmatters/configuration/validate # Cortex Command Line Interface Source: https://docs.cortex.io/configure/cortex-command-line-interface The Cortex Command Line Interface (CLI) is an open‑source, Python‑based command‑line tool for interacting with the [Cortex API](/api). It’s published as the `cortexapps-cli` package on PyPI and maintained in the public [`cortexapps/cli` GitHub repository](https://github.com/cortexapps/cli). You can use it to call Cortex APIs from scripts (for example, managing catalog entities and performing bulk operations). ### Installation For installation, usage, and examples, see the [Cortex CLI project in PyPi](https://pypi.org/project/cortexapps-cli/). ### Contributions For bug reports or other issues, customers are encouraged to open GitHub issues in the [Cortex CLI GitHub repository](https://github.com/cortexapps/cli). # GitOps for Cortex overview Source: https://docs.cortex.io/configure/gitops Cortex supports a [GitOps approach](https://about.gitlab.com/topics/gitops/): instead of managing your catalog in the Cortex UI, you define it in code. Entities, Scorecards, and Workflows are described in descriptor files that live in your Git repository, and Cortex treats those files as the source of truth. This keeps the definition of a system in the same place as the system itself, so your catalog can evolve alongside the code it describes. The GitOps model offers several benefits: * Your metadata is version-controlled. * The repository where your code lives is also the source of truth for information about it. * You always own the data. * You can track GitOps changes in GitOps logs. * Users must have the `View GitOps Logs` permission. > [!TIP] > > Want to learn more? Check out the Cortex Academy course on [using GitOps](https://academy.cortex.io/courses/gitops-dq31). ## How GitOps works in Cortex With GitOps, you manage entities, Scorecards, and Workflows with descriptor files that live in your Git repository. An entity descriptor, also called a Cortex YAML, describes an entity in your catalogs. You can keep each entity's descriptor in the repository it describes, or keep all of your definitions together in a single repository. For Bitbucket, GitHub, and GitLab, Cortex checks for a `cortex.yaml` or `cortex.yml` file anywhere in the default branch, and processes any changes you push to that branch. If you keep all of your definitions in a single repository, Cortex checks for YAML files in the `.cortex` directory. Cortex finds Scorecards and Workflows by location rather than by filename. Scorecard definitions are read from the `.cortex/scorecards` directory, and Workflow definitions from `.cortex/workflows`. For more information, refer to [Scorecards as code](/standardize/scorecards/scorecards-as-code) and [Workflows as code](/streamline/workflows/workflows-as-code). > [!TIP] > > Cortex recommends storing `cortex.yaml` in the repository root or `basePath`. If you turn on GitOps-based auto-archival, Cortex archives an entity when its descriptor file is deleted from the repository. Cortex checks for deleted files only, so moving a file doesn't archive the entity. For more information, refer to [Archiving entities automatically](/ingesting-data-into-cortex/entities-overview/entities/archiving-entities/auto-archive). ### **GitOps repository structure** There are two ways to structure descriptor files in your Git repository. **Option 1: One `cortex.yaml` per repository** Each repository contains a `cortex.yaml` file, stored anywhere in the default branch. This is commonly used for a one-to-one mapping, where the repository represents its Cortex entity. It's supported for Bitbucket, GitHub, and GitLab. For Azure DevOps, the `cortex.yaml` file must be stored at the root of the default branch. To work around this in unique cases, refer to [Using multiple source directories](/configure/gitops/using-gitops-for-cortex#using-multiple-source-directories). **Option 2: A single repository for all descriptors** All descriptor YAMLs are stored in one repository, under a `.cortex` directory, in the subdirectories `catalog`, `domains`, `teams`, `scorecards`, and `workflows`. This is supported for all Git providers. * The `catalog` subdirectory contains services and custom entities. * The `domains` subdirectory contains domains. * The `teams` subdirectory contains teams. * The `scorecards` subdirectory contains Scorecards as code. * The `workflows` subdirectory contains Workflows as code. The following example shows a single repository structure. Entity descriptor files are listed under subdirectories for `catalog`, `domains`, `teams`, `scorecards`, and `workflows`: ``` . └── .cortex ├── catalog │ ├── database.yml │ ├── s3-bucket.yml │ ├── auth-service.yml │ ├── my-custom-entity.yml │ ├── events │ │ ├── event-router.yml │ │ └── event-archiver.yml │ └── payments │ ├── payment-api.yml │ └── payment-worker.yml ├── domains │ ├── billing-domain.yml │ └── health-domain.yml ├── teams │ ├── eng-team.yml │ └── platform │ └── sre-team.yml ├── scorecards │ ├── production-readiness.yml │ └── security.yml └── workflows ├── onboarding.yml └── incident-response.yml ``` Note the following: * Catalogs cannot be created via GitOps—they can only be defined in the Cortex UI. * The `catalog` subdirectory contains the YAML files for services and custom entities, regardless of which catalogs the services and custom entities are organized into. * For example, you might have created catalogs for `API` and `Library`, and those catalogs might contain services or custom entities. In your Git repository, those entities will appear in the `catalog` subdirectory. * You can organize YAML files into subdirectories nested under any of the `catalog`, `domains`, `teams`, `scorecards`, and `workflows` subdirectories. Cortex searches each of these recursively, so it finds YAML files at any depth. * For example, Cortex finds both `.cortex/catalog/payment-api.yaml` and `.cortex/catalog/events/payment-api.yaml`. Each of these directories must be directly inside `.cortex`, so Cortex doesn't find `.cortex/internal/catalog/payment-api.yaml`. * Directory names must match exactly. Cortex only searches the `catalog`, `domains`, `teams`, `scorecards`, and `workflows` subdirectories, so similarly named directories such as `.cortex/catalog-pilot/` or `.cortex/catalog_audit/` are ignored. ### Switching from the Cortex UI to GitOps Cortex's Git integrations parse entity descriptor files automatically, so switching to GitOps is straightforward. Cortex recommends switching after Cortex has been broadly rolled out to your organization. Give developers a chance to explore Cortex in the UI first, and set a threshold for when your organization is ready to cut over. You don't have to move everything at once, since you can [enable GitOps for each entity type](/configure/gitops/using-gitops-for-cortex#step-1-disable-ui-editing) separately. ### Using both the UI and GitOps You can mix UI and GitOps management, but the details differ depending on what you're managing. **Entities** You can combine the two approaches for an entity type by enabling UI editing and disabling UI importing. New entities are then created through GitOps, but you edit them in the Cortex UI. Cortex doesn't process edits you make through GitOps, so the UI becomes the source of truth for changes: 1. From the main sidebar, click your avatar in the bottom-left corner. 2. Select **Settings**. 3. In Settings menu, locate the **Workspace** section, then select **GitOps**. 4. From the **Entities** tab, scroll to the **Options by type** section. 5. Toggle on **Enable UI editing for new entity types**. 6. Ensure that **Enable UI importing for new entity types** is toggled off. **Workflows** GitOps editing applies only to Workflows that are backed by a YAML file, so you can manage some Workflows through GitOps and others through the UI at the same time. You can still create and delete Workflows in the UI, and you can still edit any Workflow that isn't managed through GitOps. **Scorecards** When you enable GitOps editing for Scorecards, you can't edit any Scorecard in the UI, including Scorecards you originally created there. All edits must happen in the YAML file in your Git repository. You can still create and delete Scorecards in the UI. # GitOps logs Source: https://docs.cortex.io/configure/gitops/gitops-logs GitOps logs serve as a valuable tool to understand and monitor changes made specifically through GitOps within your workspace. This feature provides a comprehensive record of changes made via GitOps. This record includes, but is not limited to, which repository a change was made in, the commit details, the number of commits made, the entities affected, and any validation errors that occurred during the change process. GitOps logs are a great way for you to track changes, identify discrepancies, and gain a holistic view of changes that have been made in your workspace. You can access the GitOps log through the Cortex UI or the public API endpoint. ## Accessing GitOps logs through the Cortex UI To view GitOps logs, navigate to [**Settings > GitOps** **logs**](https://app.getcortexapp.com/admin/settings/gitops-logs). ![](https://mintcdn.com/cortex-290c0c42/OnaYqLHqq-U_XM2R/images/gitops-logs.jpg?fit=max\&auto=format\&n=OnaYqLHqq-U_XM2R\&q=85\&s=5edc4a8e852067b713f6008ae198e2c5) The GitOps logs page lists events and associated details. Click into a log to view a side panel with more information: * **Repo:** Name of the repository a change was made in. * **Timestamp**: When the change was made. * **Commit sha:** Record of the changes made in associated repository. * **Branch**: Which branch the change was made in. * **# of commits:** Total number of commits. * Under the **Changes** tab, a list of the affected files. * You can toggle on **Show only with impacted entities** to view changes that impacted entities. * Under the **Omitted files** tab, a list of files that were omitted during the commit. * Under the **Event processing tab**, a list of related events. ![A GitOps log displays relevant information about the activity.](https://mintcdn.com/cortex-290c0c42/OnaYqLHqq-U_XM2R/images/gitops-log-example.jpg?fit=max\&auto=format\&n=OnaYqLHqq-U_XM2R\&q=85\&s=afe348d8487a6dbfcc6e457707821dc7) ### Accessing Audit logs through the public API endpoint GitOps logs can also be accessed through the public API endpoint. Please refer to our [GitOps logs API documentation](/api/rest/gitops-logs) to learn how to retrieve GitOps logs. # Using GitOps for Cortex Source: https://docs.cortex.io/configure/gitops/using-gitops-for-cortex ### GitOps considerations Before getting started, note the following: * Cortex will only check for files in the repository's default branch, unless [otherwise specified](/configure/gitops/using-gitops-for-cortex#additional-configuration-options-for-gitops). Cortex defaults to `main` if there is no default branch defined. * Cortex does not delete Scorecards if a corresponding Scorecard YAML is deleted. You can enable automatic archival of entities through GitOps by toggling on **"Enable auto archiving of services"** in [the Entities settings page](https://app.getcortexapp.com/settings/entities). Read more in the [auto-archival docs](/ingesting-data-into-cortex/entities-overview/entities/archiving-entities/auto-archive). * Domain, team, and Scorecard definitions must be in the `.cortex/domains`, `.cortex/teams`, and `.cortex/scorecards` folders, respectively, or in any subdirectory beneath them. * The hierarchy of entities in Cortex is based on that hierarchy being defined in the entity's YAML file; Cortex does not set hierarchies or entity relationships based on a YAML file's location in your repository. * Learn more about defining a hierarchy in the YAML in the [Team docs](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/teams#adding-a-team-in-yaml-via-gitops), [Domain docs](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/domains#adding-a-domain-in-yaml-via-gitops), and the [Entity relationship docs](/ingesting-data-into-cortex/entities-overview/entities/defining-relationship-types/managing-relationships#creating-relationship-connections-via-an-entity-descriptor). * You can define any number of entities within the same repository. * GitOps is not designed for high-volume or bulk updates. We recommend keeping batch sizes under 1,000 updates per hour to avoid hitting your Git provider's rate limits. For large-scale entity updates, we recommend using the [Cortex API](/api/rest/catalog-entities). * The recommended placement for entity descriptor files is in the root of the repository, or in the appropriate `.cortex/catalog` folder. * For Bitbucket, Bitbucket Server, GitHub, or GitLab, the descriptor can be located anywhere in the repository as long as the file is named `cortex.yaml` or `cortex.yml`. You can also use a single repository and place descriptor files in the appropriate `.cortex` subdirectory. * For Azure DevOps, the `cortex.yaml` file must be stored at the root of the repository of the default branch. It is possible to [work around this](/configure/gitops/using-gitops-for-cortex#using-multiple-source-directories) for unique cases. You can also use a single repository and place descriptor files in the appropriate `.cortex` subdirectory. * When using a single repository structure, [as described in this example](/configure/gitops#gitops-repository-structure), the `.cortex` subdirectory only respects `catalog`, `scorecards`, `domains`, `workflows`, and `teams` subdirectories. Do not place an entity's YAML file in the `.cortex` directory unless it is in one of the supported subdirectories. For additional information on using GitOps to manage Scorecards and Workflows, see [Scorecards as code](/standardize/scorecards/scorecards-as-code) and [Workflows as code](/streamline/workflows/workflows-as-code). ### Step 1: Disable UI editing When following a GitOps approach, you make changes to entities via their entity descriptor file and sync the changes using a Cortex git integration or programmatically using the [Cortex API](/api/rest/catalog-entities). You must disable UI editing to ensure consistency. If the UI editor is enabled, then changes made via git will not be processed in Cortex. Confirm that the Cortex UI editor is **disabled** for each entity type you want to use a GitOps approach for: 1. Navigate to the [**GitOps** page in Settings](https://app.getcortexapp.com/settings/gitops). 2. Disable the toggles for UI editing next to services, domains, teams, and other entity types. To learn about other GitOps settings, see the [GitOps settings documentation](/configure/settings/gitops-settings). ### Step 2: Configure a Git integration Before you can move to a GitOps approach, Cortex must be integrated with GitHub, GitLab, Azure DevOps, or Bitbucket. Expand the tabs below for instructions on each provider. > **Azure DevOps** > > **Azure DevOps** > > 1. Follow the instructions to [integrate Cortex with Azure DevOps](/ingesting-data-into-cortex/integrations/azuredevops). > 2. Add a webhook for Azure DevOps: > 1. In Cortex, navigate to [Settings > Azure DevOps](https://app.getcortexapp.com/settings/azuredevops) and validate your Azure DevOps integration. > 2. Click **Create a new webhook** and copy the unique webhook URL. > 3. Follow the instructions from Azure on [adding a webhook](https://docs.microsoft.com/en-us/azure/devops/service-hooks/services/webhooks?view=azure-devops). > * Set the event type to `Code pushed` and use the URL from the previous step. > **Bitbucket** > > The Bitbucket integration is pre-configured with the ability to use the GitOps approach in Cortex. If you are using Bitbucket Server, you will also need to add a webhook. > > 1. In Bitbucket, enable development mode. > * You can find this setting in your Bitbucket instance at `https://bitbucket.org//workspace/settings/addon-management/`. > 2. Follow the instructions to integrate Cortex with Bitbucket. > * If you are not using Bitbucket Server, then your integration is complete and you are ready to use GitOps. > 3. If you are using Bitbucket Server, add a webhook for Bitbucket: > 1. Navigate to [Settings > Bitbucket](https://app.getcortexapp.com/settings/bitbucket) and validate your configuration. > 2. Enter a secret token for your Bitbucket Server webhook. > 3. Click **Create a new webhook** and copy the unique webhook URL. > 4. Follow the [Bitbucket Server instructions](https://confluence.atlassian.com/bitbucketserver/manage-webhooks-938025878.html) for adding a project-level or repository-level webhook. > * Set the event type to `repository push`. Use the secret and the URL from the previous steps. > > If you're using a monorepo, see the section below: [Using GitOps for a monorepo in Bitbucket](/configure/gitops/using-gitops-for-cortex#using-gitops-for-a-monorepo-in-bitbucket). > **GitHub** > > The [Cortex app for GitHub](https://github.com/apps/cortex-app) is pre-configured with the ability to use the GitOps approach in Cortex. If you configure the integration using a personal access token, you will also need to add a webhook. > > 1. Follow the instructions to [integrate Cortex with GitHub](/ingesting-data-into-cortex/integrations/github). > * If you integrated using the Cortex app, then your integration is complete and you are ready to use GitOps. > 2. If you configured your GitHub integration using a personal access token, create a webhook: > 1. Enter a secret passphrase for your GitHub webhook in the **Secret** field. > 2. After saving the passphrase, a unique webhook URL is displayed. > * The URL will end with `{alias}` - make sure to replace this with the alias you used when configuring your GitHub integration. > 3. Follow the instructions from GitHub on [creating a webhook](https://docs.github.com/en/webhooks/using-webhooks/creating-webhooks). Cortex recommends adding an [organization webhook](https://docs.github.com/en/webhooks/using-webhooks/creating-webhooks#creating-an-organization-webhook), but you can also define the webhook for a [repository in the org](https://docs.github.com/en/webhooks/using-webhooks/creating-webhooks#creating-a-repository-webhook). > * Set the content type to `application/json`. Use the secret passphrase and the URL from the previous steps. > **GitLab** > > 1. Follow the instructions to [integrate Cortex with GitLab](/ingesting-data-into-cortex/integrations/gitlab). > 2. Create a webhook: > 1. In the [GitLab settings](https://app.getcortexapp.com/settings/gitlab) in Cortex, click **Create a new token**. > * The token and the webhook URL will be displayed. > 2. In GitLab, [create a system hook](https://docs.gitlab.com/ee/administration/system_hooks.html#create-a-system-hook)(recommended) or a [project hook](https://docs.gitlab.com/ee/user/project/integrations/webhooks.html#configure-a-webhook). > * Enable `Push events` for the webhook. Use the token and the webhook URL from the previous steps. Once GitOps is enabled, Cortex will detect push events in your repositories. For the first webhook for a given repository, Cortex looks for the `cortex.yaml` files and processes them. For subsequent webhooks, Cortex only processes files with a change in the webhook event. A maximum of 3,000 changed files will be reported per commit. **Additional configuration** Cortex's out-of-the-box GitOps configuration suits most common use cases, but you may have a scenario that requires additional configuration, such as a monorepo in Bitbucket, a repository with different projects in multiple branches, a need to restrict which repositories to import from, and more. See [Additional configuration options for GitOps](/configure/gitops/using-gitops-for-cortex#additional-configuration-options-for-gitops) below for more information. **Multi-account configuration** It is possible to configure multiple account integrations with Cortex for each of the git integrations. If you're creating or editing a `cortex.yaml` in the non-default configuration, you must reference the alias you used for that integration when you configured it. For example, if you added a second GitHub configuration called `non-default-example`, you would define the following block in the entity descriptor: ```yaml theme={null} x-cortex-git: repository: organization/non-default-example-repo alias: non-default-example ``` > [!WARNING] > > If you do not define the `alias`, Cortex will use the default configuration when processing changes made to the `cortex.yaml` file. If a repository is not included in the default configuration, changes will not be processed via GitOps. ### Step 3: Get started with managing entities After completing your GitOps configuration, you can start managing entities via GitOps. Before following these steps: * We recommend reviewing the [Entities documentation](/ingesting-data-into-cortex/entities-overview/entities) to understand the basics about working with entities in Cortex. > **Create an entity** > > **Create an entity** > > To create a new entity from a new repository: > > 1. Create a repository in your git account. > 2. Create a new `cortex.yaml` or `cortex.yml` file in the repo you just created, including the entity's details. > 3. Commit and push your changes. > > The entity will now exist in your repository and in the Cortex UI. > > For example: > > ```yaml theme={null} > openapi: 3.0.1 > info: > title: Example Entity > x-cortex-git: > github: > repository: org/repo > x-cortex-tag: example-entity > x-cortex-owners: > - name: test-team > type: group > provider: CORTEX > x-cortex-type: service > x-cortex-custom-metadata: > test: 123 > ``` > > > [!TIP] > > > > The GitHub app has a built-in linter, so if an entity descriptor file is invalid, the GitHub app will comment on the pull request with outstanding issues. > > Learn more about creating entity YAMLs in [Defining entities via YAML file](/ingesting-data-into-cortex/entities-overview/entities/yaml). > > **Verify that your entity was created** > > To verify that the new entity was created: > > * View the [GitOps logs page in Cortex](https://app.getcortexapp.com/settings/gitops-logs), which displays all changes made in your Cortex workspace. If your entity creation was successful, you should expect to see it at the top of the list. > * You must have the `View GitOps logs` permission to view this page. > > * Search the [**Catalogs > All entities** page](https://app.getcortexapp.com/admin/entities) for the new entity's name or tag. If your creation was successful, it will appear in the search results. > > > [!NOTE] > > > > If you do not see your changes, refresh the browser window where you are logged in to Cortex. > **Edit an entity** > > **Edit an entity** > > Any changes you commit to an entity will appear under **Recent activity** on the entity page overview. > > 1. Navigate to the YAML file for an entity. > 2. Add data to the entity > 3. Commit and push your changes. > > The edits now exist in your repository and on the entity in the Cortex UI. On the entity details page, the update will appear under **Recent activity**. > > > [!WARNING] > > > > If UI editing is **enabled** for an entity type, any changes you commit to that entity will **not** be reflected in Cortex. > > **Verify that an entity was edited** > > To verify that an entity was edited: > > * View the [GitOps logs page in Cortex](https://app.getcortexapp.com/settings/gitops-logs), which displays all changes made in your Cortex workspace. If your entity edit was successful, you should expect to see it at the top of the list. > * You must have the `View GitOps logs` permission to view this page. > * Search the [**Catalogs > All entities** page](https://app.getcortexapp.com/admin/entities) for the entity's name or tag. If your edit was successful, it will appear in the search results. > > If UI editing is enabled and UI importing is disabled, changes will display in GitOps logs and under an entity's recent activity, but those changes will not process. The **Entities** column in GitOps logs will show `0 entities` if this is the case. When you open the commit, the panel will show **No changes processed**, and the `cortex.yaml` file will appear under **Omitted files**. > [!TIP] > > In the Cortex UI on an [entity details page](/ingesting-data-into-cortex/entities-overview/entities/details), entities created or updated via GitOps will display the file path of the entity's YAML file and a preview of the last GitOps log. You must have the `View GitOps logs` permission. ## Additional configuration options for GitOps Cortex's standard GitOps configuration suits most common use cases: * Single or many projects per repo * Only one branch needs to be processed for `cortex.yaml` * The `cortex.yaml` file is in the default or `main` branch However, there may be scenarios that require special setups, such as the following examples: * **Monorepos in Bitbucket:** Multiple projects in a single repo, split into subfolders. * **Branches:** Non-main or non-default branches, or different projects in multiple branches. See the sections below for more information about special configurations. ### Restrict which repositories to import from By default, Cortex will check all repositories for services, domains, teams, and other entity types. It is possible to restrict which repositories entities are imported from: 1. Navigate to the [**Settings > GitOps**](https://app.getcortexapp.com/settings/gitops). 2. Under **Options by entity type**, find the dropdown labeled **Entity GitOps repository allowlist for new entity types**. 3. Select the repositories you want to import from. When one or more repositories are selected for a given entity type, Cortex will only check those repos for changes to the `cortex.yaml` file. > [!WARNING] > > If you make changes in a repo that is not designated on the allowlist, Cortex will not process those changes. ### Using GitOps for a monorepo in Bitbucket Using GitOps with a monorepo - one Git repository with multiple entities - is supported out-of-the-box for Azure DevOps, GitHub, and GitLab when you use the `basepath` field to specify the subdirectory in the entity descriptor (see an example of this in the docs for [Azure DevOps](/ingesting-data-into-cortex/integrations/azuredevops#editing-the-entity-descriptor), [GitHub](/ingesting-data-into-cortex/integrations/github#entity-descriptor), and [GitLab](/ingesting-data-into-cortex/integrations/gitlab#editing-the-entity-descriptor)). When using a monorepo with Bitbucket, you must use the `cortex-properties.yaml` file: * The file is automatically processed, just like the entity descriptor. * It should live in the `default` branch for the repo, **regardless of which branches it states Cortex should use to find entity descriptor files**. * When using the `cortex-properties.yaml file`, the `basePath` may not function as expected if you have service code elsewhere in your repository. Note that this file should only be used for custom workflows, such as using monorepos in Bitbucket or using a non-default branch as the home for your entity descriptor files. ### Using GitOps in a non-default branch You can configure Cortex to automatically process `cortex.yaml` files in non-standard branches, multiple branches, or both. Consider the following example scenario: * You have a project where `main` is protected and is the default branch. * You want to include `cortex.yaml` in the `develop` branch. * You also have a separate project version in a `staging` branch with its own `cortex.yaml` file. To represent this: * Add a `cortex-properties.yaml` file in the default branch of your repo * Define the `branches` field with a list of branches to process. * The default branch **must** be explicitly defined if you are using an advanced configuration and you want Cortex to search for a `cortex.yaml` file in the default branch. ```yaml theme={null} branches: - main - develop - staging ``` If your `cortex-properties.yaml` file does not contain a `branches` field, Cortex will continue to process the `default` branch. Cortex will process the most recently modified `cortex.yaml` file across all branches listed in the `cortex-properties.yaml` file. > [!NOTE] > > When using the `branches` field in your `cortex-properties.yaml` file, make sure to include the default branch if you want Cortex to continue looking for a `cortex.yaml` file in the default branch. ### Using multiple source directories When using Azure DevOps for GitOps, you can configure Cortex to look for `cortex.yaml` files in multiple subdirectories. Consider the following example scenario: * You have a monorepo structure where all projects live in a single repository. * Each project lives in a subdirectory in the main repository (`project1/`, `project2/`, etc.). * Each project has its own `cortex.yaml` file. To represent this: * Add a `src-dirs` field in a `cortex-properties.yaml` file at the root of the repository, containing a list of directories to process. ```yaml theme={null} src-dirs: - project1 - project2 ``` Cortex will still process any `cortex.yaml` file found in the root of the repository. ## Troubleshooting and FAQ See frequently asked questions below. > **Conflicts between UI editing, GitOps, and the Cortex API** > > If GitOps has previously been enabled, but UI editing is temporarily turned on, any changes made in Cortex to applicable entities will not be reflected in Git. When the file is next changed through your Git provider, it will override changes made in the UI. > > The last received change in a `cortex.yaml` file will override previous changes, whether it originated from the create/update entity API or a push from your Git provider. Changes are not appended and the last submitted entire file takes precedence, so fields omitted in `cortex.yaml` will be removed. > **Will my cortex.yaml file be picked up immediately?** > > If you already have a `cortex.yaml` file when you set up GitOps, Cortex will automatically process it. However, the file **will not** be processed until UI editing is **disabled**. > **The entity I created appears in GitOps logs, but displays 0 entities 0 scorecards in the Entities column.** > > First, use the [YAML linter](https://app.getcortexapp.com/admin/yaml-linter) to validate your `cortex.yaml` file. Then, confirm GitOps settings are configured correctly: > > * Make sure [UI editing is **disabled**](/configure/gitops/using-gitops-for-cortex#step-1-disable-ui-editing) for the entity type that you're trying to create. > * Check repositories in the GitOps [repository allowlist](/configure/gitops/using-gitops-for-cortex#restrict-which-repositories-to-import-from). If there are repositories selected for the entity type you're working with, confirm that you're working from an allowed repo. > **My entities were syncing from a directory under .cortex, and now they aren't.** > > Cortex matches directory names exactly. It doesn't scan similarly named directories such as `.cortex/catalog-pilot/`, `.cortex/catalog_v2/`, or `.cortex/teams-old/`. > > If files in one of these directories were being discovered before, move them into `catalog`, `domains`, `teams`, `scorecards`, or `workflows`, or into a subdirectory beneath one of them. Cortex doesn't remove entities that were already created from those directories. They stop receiving updates, and you can archive or delete them when you're ready. # Workspace Settings Source: https://docs.cortex.io/configure/settings Customize your Cortex workspace, [manage users](/configure/settings/managing-users), view [audit logs](/configure/settings/audit-logs), and more in Settings. To access Settings, click your avatar in the lower left corner, then click **Settings**. * If you have the `Edit settings` permission, you will see the general settings configuration page. If you do not have this permission, you will see your notification subscriptions page. ![Click your avatar, then click Settings.](https://mintcdn.com/cortex-290c0c42/K6GZjp5BfPGK-s1-/images/settings-link.jpg?fit=max\&auto=format\&n=K6GZjp5BfPGK-s1-\&q=85\&s=bb7bf20004405a5cf176a55ca60eb977) ## Types of workspace settings In Cortex, you can configure personal preferences, workspace look and feel, entity and feature settings, authentication and access, identity mappings, and integrations. The required permissions differ depending on which settings you need to access. See the [permissions included in default roles](/configure/settings/managing-users/permissioning#default-roles) and the [permissions you can add to custom roles](/configure/settings/managing-users/permissioning/custom-roles#available-permissions-for-custom-roles). ### Personal preferences Configure your own access tokens, group subscriptions, identity mappings, and notifications. ![Access personal preferences in the Settings.](https://mintcdn.com/cortex-290c0c42/wjT-J8PNs9MwpcFs/images/personal-preferences.jpg?fit=max\&auto=format\&n=wjT-J8PNs9MwpcFs\&q=85\&s=0aab18f322c3b3fac2b8901e7db6e4e3) ### Workspace * View billing information * Configure the [look and feel for the workspace](/configure/settings/workspace-customization), plugins, and Eng Intelligence * Configure Eng Intelligence [custom metrics](/improve/eng-intelligence/custom-metrics#define-custom-metrics-and-add-metric-data), [issue groupings for Jira metrics](/improve/eng-intelligence/eng-intelligence#issues-completed), and [user labeling](/improve/eng-intelligence#create-and-manage-user-labels-for-grouping) * Configure entity settings, including auto import (for [AWS](/ingesting-data-into-cortex/integrations/aws#enable-automatic-import-of-aws-entities), [Azure Resources](/ingesting-data-into-cortex/integrations/azureresources#enable-automatic-discovery-of-azure-resource-entities), and [Google](/ingesting-data-into-cortex/integrations/google#enable-automatic-import-of-google-entities)), [auto-archival](/ingesting-data-into-cortex/entities-overview/entities/archiving-entities/auto-archive), team member role sync, and [data verification](/configure/settings/entity-settings/verification) * Configure [GitOps settings](/configure/gitops), including processing, linter checks, and whether to enable or disable UI editing per entity type * Adjust [notification](/configure/settings/notifications) options for the workspace * Change the default [relationship graph](/ingesting-data-into-cortex/entities-overview/entities/relationship-graph#adjust-appearance-settings) view * Configure [Scorecard](/standardize/scorecards) preferences and evaluation window, review rule exemptions, and see all outdated CQL expressions being used * ```
Manage workspace customization in Workspace settings.
``` ### Authentication and access * View a list of [API keys](/configure/settings/api-keys) and [secrets](/configure/settings/api-keys/secrets), create API keys and secrets * View Cortex workspace [audit logs](/configure/settings/audit-logs), [GitOps audit logs](/configure/gitops/gitops-logs), and [notification logs](/configure/settings/notifications/logs) from the last 30 days * View breaking API change notifications * This feature is available in beta. Please contact your Cortex Customer Success Manager for access. * Configure the [IP allowlist](/configure/settings/ip-allowlist) * Configure [OpenID Connect applications](/configure/settings/managing-users/configuring-sso) and [SCIM settings](/configure/settings/managing-users/scim/okta-scim) * Configure [roles and permissions](/configure/settings/managing-users/permissioning) ![Access authentication settings in the Settings page.](https://mintcdn.com/cortex-290c0c42/WsEW6MxYeKygvxWi/images/auth-settings.jpg?fit=max\&auto=format\&n=WsEW6MxYeKygvxWi\&q=85\&s=ac8b0e7c0e6041cd01aa3d967a101602) ### Identity mappings Configure [identity mappings](/configure/settings/managing-users/identity-mapping) for your configured integrations. ![Configure identity mappings in the Settings page.](https://mintcdn.com/cortex-290c0c42/OnaYqLHqq-U_XM2R/images/identity-mappings-settings.jpg?fit=max\&auto=format\&n=OnaYqLHqq-U_XM2R\&q=85\&s=9de7a2ca838b6419dfd271914c131764) ### Integrations Configure your [third-party integrations](/ingesting-data-into-cortex/integrations). ![](https://mintcdn.com/cortex-290c0c42/4tRxSDOxhMkPeY0E/images/integration-settings-page.jpg?fit=max\&auto=format\&n=4tRxSDOxhMkPeY0E\&q=85\&s=01a7463b557388b90fc56883332116dd) # API keys, secrets, and tokens Source: https://docs.cortex.io/configure/settings/api-keys Cortex provides three credential types to help you manage authentication and access securely. API keys grant programmatic access to Cortex data and integrations, [secrets](/configure/settings/api-keys/secrets) store sensitive credentials for use across your configurations, and [personal access tokens](/configure/settings/api-keys/personal-tokens) allow individual users to interact with the Cortex API under their own permissions. Using the right credential type for each use case helps minimize risk and maintain the principle of least privilege. ## Managing API keys API keys enable programmatic access to your Cortex data, from high-level Scorecard stats to detailed information about specific entities in your catalogs. You can manage API keys through the Cortex UI or via the API. Both require the `Edit API keys` permission. For a full reference of available API key endpoints, see [API Keys](/api/rest/api-keys). ## Creating an API key in Cortex Follow the steps below to create an API key in Cortex. Note that you must have the `Edit API keys` permission to create or delete API keys, or to edit their name or description. > [!NOTE] > > Assign only the permissions necessary for the API key's intended purpose. API keys support the same [default permissions](/configure/settings/managing-users/permissioning) and [custom roles](/configure/settings/managing-users/permissioning/custom-roles) available to individual users. There is no limit to the number of API keys you can create! 1. From the main sidebar, click your avatar in the bottom-left corner. 2. Click **Settings**. 3. From the **Settings** menu, scroll to the *Security and access* section, then select **API keys**. 4. Click **Create new key** in the upper-right corner. 5. Do the following: 1. Below **Name**, enter a name for the key (required). 2. Below **Description**, enter a brief overview of the key. > [!NOTE] > > As a best practice, include details about what the API key is used for. This helps ensure that other users do not accidentally delete an important API key. 3. From the *Role* drop-down menu, select the permissions level for the key (required). 4. Below **Expiration date**, set an expiration date for the key. The key automatically expires at the end of the chosen day based on the current time zone. 6. Click **Create API key**. The key is created and displayed. Copy the key and store it in a secure location, as it will not be displayed again after you refresh or navigate away from the page. > [!NOTE] > > The key is only displayed once! Copy it and store it in a secure location before navigating away from this page. Cortex only retains the last 4 digits of the key for reference; the remainder is encrypted and cannot be recovered. ## Modifying an API key You can update the name and description of an API key after it has been created. > [!NOTE] > > The key value itself cannot be modified. To change it, delete the existing key and create a new one. Learn more about [best practices for API key rotation below](/configure/settings/api-keys#best-practices-for-api-key-rotation). 1. From the main sidebar, click your avatar in the bottom-left corner. 2. Click **Settings**. 3. From the **Settings** menu, scroll to the *Security and access* section, then select **API keys**. 4. Locate the API key you want to edit, then click the **pencil icon** next to that key. 5. Do any or all of the following: * Below **Name**, enter a new name. * Below **Description**, enter a new or updated overview of the key. * Below **Expiration date**, enter a new or updated expiration date. 6. Click **Save**. The key is updated. ## Requiring an expiration date for API keys Cortex requires all new API keys to have an expiration date. For existing keys, an expiration date is optional. > [!NOTE] > > API key expiration is enforced globally. Once enabled, all newly created API keys in your Cortex workspace are subject to the specified maximum lifetime. 1. From the main sidebar, click your avatar in the bottom-left corner. 2. Click **Settings**. 3. From the **Settings** menu, scroll to the *Security and access* section, then select **Security policy**. 4. Toggle on **Require API token expiration**. 5. Below *Maximum lifetime for new tokens*, enter the number of days after which new tokens will expire. > [!NOTE] > > Maximum lifetime cannot exceed 400 days. 6. Click **Save**. API keys created going forward will expire after the maximum lifetime you specified in step 5. ## API key and personal access token expiration notifications Keys and tokens with an expiration date trigger notifications before they expire. Recipients receive a reminder seven (7) days before the expiration date, followed by a second reminder the day before, giving time to rotate or renew before it becomes invalid. Who receives these notifications depends on the type of credential: * **API keys:** Notifications go to all workspace users with the `Edit settings` permission (effectively, workspace admins). The notification states that one or more API keys will expire and links to the API keys settings page. * **Personal access tokens:** Notifications go only to the individual user who owns the token. The notification states that one or more personal access tokens will expire and links to the personal access tokens settings page. Both notification types follow the same timing: 7 days before expiration, and 1 day before expiration. # Personal tokens Source: https://docs.cortex.io/configure/settings/api-keys/personal-tokens Personal access tokens provide Cortex users with a way to access data and edit entities and Scorecards. Similar to API keys, you can use personal tokens to make calls through API endpoints. **Permissions for personal tokens directly mirror your own user** [**permissions**](/configure/settings/managing-users/permissioning). All users, including users with the `Viewer` role, can create a personal token. > [!WARNING] > > If you attempt to make a call through endpoints not within your user permissions, this will result in a 403 error. **To create a personal access token**: 1. From the main sidebar, click your avatar in the bottom-left corner. 2. Click **Settings**. 3. From the **Settings** menu, locate the *Preferences* section, then select **My access tokens**. 4. In the upper-right corner, click **Create new token**. 5. Do the following: 1. Below **Name**, enter a name for the token (required). 2. Below **Description**, enter a brief overview of the token. > [!NOTE] > > As a best practice, include details about what the token is used for. If you add multiple tokens, the description can help clearly identify and differentiate between the tokens listed on this page. 3\. Below **Expiration date**, set an expiration date for the token. The key automatically expires at the end of the chosen day based on the current time zone. 6. Click **Create token**. The personal access token is created. # Secrets Source: https://docs.cortex.io/configure/settings/api-keys/secrets [Secrets](https://app.getcortexapp.com/admin/settings/secrets) are encrypted variables you can store in Cortex for your workspace environment. They can be accessed for use in various Cortex features, such as: * [Plugin proxies](/streamline/plugins/creating-plugins/plugin-proxy), to allow secure authenticated access to various third-party APIs. * [Workflows](/streamline/workflows), when configuring an HTTP Request action. Secrets are securely encrypted and stored in Cortex’s database, and the secret values are not accessible via public or private APIs once saved. ### Accessing secrets Secrets can only be accessed programmatically through features in Cortex. Secrets are generally referenced by configuration of the relevant feature through a templated string that uses Mustache-like syntax to reference the secret by tag. For instance, a plugin proxy header can reference a secret similar to the following example: ```json theme={null} { "name": "Authorization", "value": "Bearer {{ secrets.my_secret }}" } ``` ## Managing secrets ### Create a secret Secrets can be created in the Cortex UI or via the Cortex API. Your user or API token must have the `Create secrets` permission. > **Cortex UI** > > For convenience, secrets can be optionally named in a human-friendly manner. For programmatic access, secrets must have a unique tag that contains only alphanumeric characters and dashes. > > To create a secret: > > 1. Go to [**Settings > Secrets**](https://app.getcortexapp.com/admin/settings/secrets) then click **Add secret**. > > ![](https://mintcdn.com/cortex-290c0c42/WsEW6MxYeKygvxWi/images/add-secret.jpg?fit=max\&auto=format\&n=WsEW6MxYeKygvxWi\&q=85\&s=d628de9c5eef35ba98b57496e5690ea6) > > 2. In the modal, configure your secret: > > * **Name**: Enter a user-friendly name. > * **Identifier**: Enter a unique identifier for the secret, made of letters, digits, and underscores. > * Note that tags cannot be edited after they are created. > * **Secret value**: Enter your secret value. > * This is usually the value of an API token or some other value from a third-party integration. > > 3. Click **Add secret**. > **API** > > It is possible to create, read, update, and delete secrets via the Cortex API. See the [API documentation](/api/rest/secrets) for more information. ### Edit secrets in the Cortex UI You must have the `Create secrets` permission to edit secrets. To edit a secret: 1. Go to [**Settings > Secrets**](https://app.getcortexapp.com/admin/settings/secrets) then click the pencil icon next to the secret you want to edit. 2. In the modal, edit the secret name. * We recommend creating a user-friendly name for the secret. 3. Click **Save**. # Audit logs Source: https://docs.cortex.io/configure/settings/audit-logs Audit logs document a detailed record of actions taken in your workspace, letting you track who made a change, when it happened, and what was altered. This includes entity edits, integration configuration changes, API key activity, and updates to custom roles and their assigned permissions. Use audit logs to investigate changes, identify discrepancies, and get a holistic view of activity across your workspace. You can access them through the Cortex UI or the [public API](/api/rest/audit-logs). ## Viewing audit logs in the Cortex UI Users with the `View Audit Logs` permission can view audit logs via the Cortex UI. 1. From the main sidebar, click your avatar in the bottom-left corner. 2. Click **Settings**. 3. From the **Settings** menu, locate the **Logging** section, then click **Audit logs**.\ ![The audit logs page in the Cortex UI.](https://mintcdn.com/cortex-290c0c42/pbVnLtaKpBTlBN5p/images/audit-logs.png?fit=max\&auto=format\&n=pbVnLtaKpBTlBN5p\&q=85\&s=0973330cc48f47099f91be4ff22fe1ff) The audit logs page displays a list of user activities. Each log entry includes the following columns: * **Actor** - Who or what performed the action: * **A user** - The user who made the change in Cortex. * **An API key** - The change was made with an API key. The entry shows the name of the key. * **Cortex** - Cortex made the change automatically on your behalf, such as syncing data from an integration or applying an update through GitOps. See [Cortex-initiated actions](#cortex-initiated-actions) for details. * **Action type** - The action performed (created, deleted, or updated). * **Object type** - The type of object that changed. See the full list of object types below. * **Object identifier** - The unique identifier of the object. * **Date** - When the action occurred. > [!WARNING] > > Note: Audit log entries only capture successful, applied changes. If an action fails, is denied by authorization, or doesn't result in an actual change (before and after states match), no entry is created. To view more information about a particular action, click its row: ![A highlighted action on the audit logs page.](https://mintcdn.com/cortex-290c0c42/pbVnLtaKpBTlBN5p/images/audit-logs-row.png?fit=max\&auto=format\&n=pbVnLtaKpBTlBN5p\&q=85\&s=401d99eff632f7bb7847af1baeb13160) A side panel opens with details about the action, including diff changes and the date and time of the action: ![The side panel provides further information about the action.](https://mintlify.s3.us-west-1.amazonaws.com/cortex-290c0c42/images/Screenshot%202026-05-22%20at%2010.13.17%E2%80%AFAM.png) ### Filtering audit logs On the audit logs page, you can narrow your search by using the filter and date range options. ![The filter icons on the audit logs page.](https://mintcdn.com/cortex-290c0c42/pbVnLtaKpBTlBN5p/images/audit-logs-filters.png?fit=max\&auto=format\&n=pbVnLtaKpBTlBN5p\&q=85\&s=a127d4beddaca28811529db1603cccea) To narrow the scope of your search, click **Filter**. You can filter by: * API key identifier * Action type * Actor IP address * Actor email * Actor type * Anonymous request type * Entity * Object type To change the date range, click **Last 7 days**. You can filter by: * Last 7 days * Last 14 days * Last 30 days * Custom date range #### How filters work You can apply multiple filters at once, and select one or more criteria within each filter. Within a single filter, multiple selections are combined with `OR`. Across different filters, selections are combined with `AND`. **Example** * Selecting `CREATE` for 'action type' and `SCORECARD` for 'object type' produces the query `create AND scorecard`. * Selecting both `CREATE` and `DELETE` for 'action type' and `SCORECARD` for 'object type' produces `(create OR delete) AND scorecard`, which returns all Scorecards created or deleted within the selected timeframe. ## **Audit log reference** ### **Object types** The following object types are included in audit logs: | Object type | Notes | | - | - | | `ACCOUNT_FLAG` | | | `ALLOW_LIST_ENTRY` | | | `API_KEY` | | | `CATALOG` | | | `CATALOG_FILTER` | | | `CORTEX_USER` | | | `CUSTOM_ROLE` | Covers changes to the role itself (name, description) | | `CUSTOM_ROLE_PERMISSIONS` | • Covers changes to the permissions granted by that role • Re-saving a custom role with no effective permission change does not produce a `CUSTOM_ROLE_PERMISSIONS` entry | | `DOMAIN` | | | `ENTITY_TYPE_DEFINITION` | | | `INITIATIVE` | | | `OAUTH_CONFIGURATION` | | | `OPENAPI_DEFINITION` | | | `PERSONAL_API_KEY` | | | `RESOURCE` | | | `SCORECARD` | | | `SECRET` | | | `SECRET_GROUP` | | | `SERVICE` | | | `TEAM` | | | `WORKFLOW` | | | Integrations | • Configuration, e.g. `OKTA_CONFIGURATION` • OAuth configuration, e.g. `BITBUCKET_OAUTH_CONFIGURATION` • OAuth registration, e.g. `JIRA_OAUTH_REGISTRATION` • On-prem configuration, e.g. `JIRA_ONPREM_CONFIGURATION` • On-prem webhook secret, e.g. `BITBUCKET_ONPREM_WEBHOOK_SECRET` • Personal configuration, e.g. `BITBUCKET_PERSONAL_CONFIGURATION` • SAST configuration, e.g. `MEND_SAST_CONFIGURATION`Unique GitHub types: • `GITHUB_APP_CONFIGURATION` • `GITHUB_APP_INSTALLATION` • `GITHUB_PERSONAL_TOKEN` • `GITHUB_WEBHOOK_SECRET` | ### **Actors** The following actor identifiers are included in audit logs: | Identifier | Notes | | - | - | | **Actor Types** | • `ANONYMOUS` • `API_KEY` • `BACKSTAGE` • `OAUTH2` • `PERSONAL_API_KEY` | | **API Key Identifiers** | When filtering by this field, enter API key names or the last 4 characters of an API key. | | **Emails** | When filtering by this field, the email address must be an exact match to the user's email. | | **IP Addresses** | | | **Anonymous Request Types** | • `API_KEY_ENTITY` • `BRAIN_AI` • `CUSTOM_INTEGRATION` • `SCORECARD_BADGES` • `SLACK_COMMAND` • Integration webhooks, e.g. `ATLASSION_WEBHOOK` | #### Cortex-initiated actions When Cortex makes a change automatically, the **Actor** column shows **Cortex** on the first line and the source of the change on the second line. Each source maps to something configured in your workspace, so you can tell why the change happened. * **Integration sync** - Cortex refreshed data from an integration you connected. This includes discovering cloud resources from Amazon Web Services (AWS), Microsoft Azure, and Google Cloud Platform (GCP), discovering entities from Git and observability providers, and mapping identities from a connected user directory. * **GitOps** - Cortex applied an entity descriptor from your repository. * **Workflow** - A Workflow that Cortex ran on your behalf made the change. * **Scaffolder** - A Scaffolder template run created or changed the entity. * **System** - A change Cortex made that doesn't fall under one of the categories above. To see what kind of object changed (for example, a cloud resource or an incident), check the **Object type** column. # Entity settings Source: https://docs.cortex.io/configure/settings/entity-settings Admins, or users with the `Configure settings` permission, can adjust system-wide settings for entities under [**Settings > Entities**](https://app.getcortexapp.com/admin/settings/entities/general). There are general settings that apply to all entity types, and settings specific to teams and domains. ![](https://mintcdn.com/cortex-290c0c42/kiI3HgqRloEyGGgk/images/entity-settings-page.jpg?fit=max\&auto=format\&n=kiI3HgqRloEyGGgk\&q=85\&s=1851be882e93bd0b61ee34331ff7aee2) ## General entity settings * **Enable changing entity type** * Allow whether or not existing entities can change their type. For example, changing the type of an entity from service to domain. Note that this could result in broken YAMLs with dependencies and hierarchies and can only be updated via the entity YAML. * **Auto import from AWS, Azure, and Google Cloud** * Enable automatic import of discovered entities of known types from [AWS](/ingesting-data-into-cortex/integrations/aws), [Azure Resources](/ingesting-data-into-cortex/integrations/azureresources), and [Google](/ingesting-data-into-cortex/integrations/google). This will import all Lambda functions and ECS services as distinct entity types. * **Always append suffixed to resource discovery** * Appends the type to the auto-generated tag for imported entities * **Auto-archiving entities by type** * Configure automatic archival for entities that are no longer detected in your integrations or whose YAML files have been deleted. Learn more in [Auto archiving entities](/ingesting-data-into-cortex/entities-overview/entities/archiving-entities/auto-archive). * **Data verification** * Set data verification policies in Cortex to make sure that entities in your Cortex workspace are accurate. Learn more in [Data verification](/configure/settings/entity-settings/verification). ## Team entity settings * **Enabled identity providers** * In this section, you can select which identity providers will be used to sync team and team memberships into Cortex. * When [importing teams](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/teams#importing-teams-from-an-integration), you will see the option to import from the enabled IdPs listed on this page. * **Auto import teams** * When enabled, any discovered teams and team relationships from [Workday ](/ingesting-data-into-cortex/integrations/workday)are automatically imported. * In order for teams to be imported, Workday needs to be enabled under the **Enabled identity providers** section on this settings page. The Workday report must include the `managerEmail` field in order for team relationships to be auto imported. * **Team ownership entity editing** * When enabled, entities can only be edited by the team that own them. You can also configure entity edit access for specific individuals on a team. Read more about this feature in [Team ownership entity editing](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/teams/team-entity-editing). * **Give edit access to all team members** * When enabled, all team members will be granted edit access to the entities owned by their team. You will not be able to turn off edit access for individual members in your teams configuration when this is enabled. ### Team member roles tab * **Sync team roles from identity providers** * When enabled, Cortex will automatically assign roles to team members based on your enabled identity providers. Leave this option disabled to assign team roles manually. * **Roles** * You can define the set of roles that can be assigned to team members. Learn more in [Adding team member roles](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/teams/team-roles#adding-team-member-roles). ## Domain entity settings * **Enable auto import of domains** * Automatically import any discovered domains and domain relationships from [ServiceNow](/ingesting-data-into-cortex/integrations/servicenow). * You must have the ServiceNow integration configured. # Data verification Source: https://docs.cortex.io/configure/settings/entity-settings/verification You can set data verification policies in Cortex to make sure that entities in your Cortex workspace are accurate. Verifications prompt owners and responsible users to check certain information, as determined by the person who created the verification period. You can [launch a Scorecard](/configure/settings/entity-settings/viewing-and-verifying-data-verifications#flagging-unverified-entities-via-a-scorecard) to streamline the process of flagging entities that haven't yet been verified, and you can [create a CQL report](/configure/settings/entity-settings/viewing-and-verifying-data-verifications#viewing-incorrect-entities-via-cql-report) to view a list of all entities that have been verified as incorrect. # Adding a verification period Users with the `Configure Verification Periods` permission can add a verification period. Optionally, but highly recommended, [configure notifications](/configure/settings/entity-settings/verification#configuring-notifications-for-data-verification) to ensure users are notified when a verification period starts and to ensure they receive reminders for entities they own that haven't yet been verified. **To add a verification period**: 1. From the main sidebar, click your avatar in the bottom-left corner. 2. Select **Settings**. 3. From the **Settings** menu, locate the **Workspace** section, then expand **Entities**. 4. Select **Data verification**. ![Data Verification](https://mintcdn.com/cortex-290c0c42/2s8kQpg4kevldgO6/images/data-verification.png?fit=max\&auto=format\&n=2s8kQpg4kevldgO6\&q=85\&s=064de4315aea0100b4186b89418d2de2) 5. On the **Data verification** page, click **+Add verification period**.\ The **Data verification** side panel opens. 6. In the side panel, enter the following: 1. **Start date** - Enter the start date for the verification period (required). This date cannot be in the past. 2. **End date** - Enter the end date for the verification period (required). This date must be at least one day after the start date. 3. **Name** - Enter a descriptive name for the data verification (required). 4. **Verification instructions** - Enter clear and concise instructions that will appear on the entity's details page. 5. **Require reason for verification** - Select this checkbox to require a reason when users mark an entity's data as invalid. 6. **Team member roles responsible for verification** - Select the Cortex users responsible for verifying data. * If you select multiple roles, any team member with one of those roles can verify data. * If you do not select a team member role, any direct member of the entity's owning team can verify data. * This setting matches against a user's [team member role](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/teams/team-roles.md) in Cortex, not their job title or their role in an external system. If your team members don't have Cortex team roles assigned, restricting verification to a role means no one can verify. See [Verifying an entity](/configure/settings/entity-settings/viewing-and-verifying-data-verifications#verifying-an-entity). 7. **Entity types** - From the dropdown, select the entities to which the verification policy applies. * Alternatively, use this dropdown to exclude specific entity types from data verification. Turn on **Exclude**, then select the types you want to leave out. 8. **Advanced options** - Expand this option to further refine your selection by including or excluding groups, or defining a CQL expression. 7. Click **Create verification period**.\ After you save a verification period, it appears in the list on the **Data verification** page within a few minutes. # Configuring notifications for data verification You can configure two notifications for entity owners: one when a verification period starts, and one that repeats while it's running. 1. From the main sidebar, click your avatar in the bottom-left corner. 2. Select **Settings**. 3. From the **Settings** menu, locate the **Workspace** section, then select **Notifications**. 4. From the **Users** tab, scroll to the **Data verification** section. ![Data Ver Notifications](https://mintcdn.com/cortex-290c0c42/2s8kQpg4kevldgO6/images/data-ver-notifications.png?fit=max\&auto=format\&n=2s8kQpg4kevldgO6\&q=85\&s=ef967e1caa3824a7b241d43c83a2de3c) 5. Toggle on the following: * **Verification period reminder** - Owners receive a notification every Monday during an active verification period, reminding them which of their entities still need to be verified. * **Verification period started** - Owners receive a notification when a verification period starts for an entity they own. For more information about notifications, refer to [Notifications](/configure/settings/notifications). # Editing or deleting a verification period Data verification periods can be edited or deleted on the **Data verification** page. 1. From the main sidebar, click your avatar in the bottom-left corner. 2. Select **Settings**. 3. From the **Settings** menu, locate the **Workspace** section, then expand **Entities**. 4. Select **Data verification**. 5. On the **Data verification** page, locate the verification you want to edit or delete. 6. Do one of the following: 1. To edit a verification, click the **pencil icon**. ![Data Ver Edit](https://mintcdn.com/cortex-290c0c42/2s8kQpg4kevldgO6/images/data-ver-edit.png?fit=max\&auto=format\&n=2s8kQpg4kevldgO6\&q=85\&s=4e1c8036fe4d6d278a5d6868a201ec00) 1. In the **Data verification** side panel, edit any necessary information, then click **Update verification period**. > [!NOTE] > > The pencil icon is greyed out for verifications that are completed or expired. 2. To delete a verification, click the **trash icon**. ![Data Ver Trash](https://mintcdn.com/cortex-290c0c42/2s8kQpg4kevldgO6/images/data-ver-trash.png?fit=max\&auto=format\&n=2s8kQpg4kevldgO6\&q=85\&s=d2627bfd6fc08d8465478934235aaec2) 1. The **Delete verification period** modal opens. Click **Delete**. # Viewing and verifying data verifications Source: https://docs.cortex.io/configure/settings/entity-settings/viewing-and-verifying-data-verifications Data verification periods are viewable at any time on the **Data verification** page. At a glance, see the status, time period, and progress for each verification. **To access the Data verification page**: 1. From the main sidebar, click your avatar in the bottom-left corner. 2. Select **Settings**. 3. From the **Settings** menu, locate the **Workspace** section, then expand **Entities**. 4. Select **Data verification**. # Viewing all entities associated with a verification You can view a list of all entities associated with a particular verification on the **Data verification** page. **To view entities associated with a verification period**: 1. From the main sidebar, click your avatar in the bottom-left corner. 2. Select **Settings**. 3. From the **Settings** menu, locate the **Workspace** section, then expand **Entities**. 4. Select **Data verification**. 5. Click into a row. \ The **Verification details** side panel opens.\ In the side panel, you can also see at a glance which entities have been verified, which user verified them, and the date of the verification. Click an entity to view its entity details page. ![Data Ver All Entities](https://mintcdn.com/cortex-290c0c42/2s8kQpg4kevldgO6/images/data-ver-all-entities.png?fit=max\&auto=format\&n=2s8kQpg4kevldgO6\&q=85\&s=b44f2c39da86b5a0a5627fa343ca9a07) # Viewing your assigned verifications Your [Engineering homepage](/streamline/homepage) shows everything you're responsible for verifying. If you own entities that need verifying, a **Pending verifications** tab appears there. If notifications are enabled, you'll also hear about a verification period when it begins and get weekly reminders while it's open. # Verifying an entity To verify an entity, you must be a direct member of a team that owns it. A few things to keep in mind: * Ownership alone isn't enough if it's indirect. If your team owns the entity through [ownership inheritance](/ingesting-data-into-cortex/entities-overview/entities/ownership/ownership-inheritance.md), or you're a member of a parent team rather than the owning team itself, you can't verify the entity. * There's no global verifier role. Workspace-level permissions, including `Configure Verification Periods`, let you set up and manage verification periods, but they don't let you verify an entity you don't own. * If the verification period specifies **Team member roles responsible for verification**, you also need one of those roles on the owning team. Without a matching role, you can't verify the entity even if you're a direct member. If you don't meet these requirements, the **Verify entity** button doesn't appear on the entity's details page. ## Verification and externally synced teams If you sync team membership from an identity provider such as Workday, GitHub, or Datadog, the sync brings in who belongs to each team, but it doesn't always bring in each member's role. Members imported without a role have no Cortex team member role at all. This matters when a verification period restricts verification to specific roles. If no one on the owning team has a matching role, no one can verify the entity, and no error is shown. To verify entities on externally synced teams, do one of the following: * Enable **Sync team roles from identity providers** under **Settings > Entities > Teams** so Cortex assigns roles based on your enabled identity providers. See [Team roles](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/teams/team-roles.md) for more information. ![Data Ver Sync Team Roles](https://mintcdn.com/cortex-290c0c42/2s8kQpg4kevldgO6/images/data-ver-sync-team-roles.png?fit=max\&auto=format\&n=2s8kQpg4kevldgO6\&q=85\&s=6a87f1a7f5772e53a827ec790395cafb) * Leave **Team member roles responsible for verification** empty when you create the verification period, so any direct member of the owning team can verify. ## How to verify an entity 1. Navigate to the [entity's details page](/ingesting-data-into-cortex/entities-overview/entities/details). 2. In the upper-right corner of the page, click **Verify entity**. If the button isn't showing, refer to [The 'Verify entity' button isn't showing](/configure/settings/entity-settings/viewing-and-verifying-data-verifications#the-verify-entity-button-isnt-showing) below. ![Data Ver Verify Entity](https://mintcdn.com/cortex-290c0c42/2s8kQpg4kevldgO6/images/data-ver-verify-entity.png?fit=max\&auto=format\&n=2s8kQpg4kevldgO6\&q=85\&s=7019f5cad0c222ed68b6e963e59f46f3) 3. Click the down arrow to the right of the **days left** tag. ![Data Ver Arrow](https://mintcdn.com/cortex-290c0c42/2s8kQpg4kevldgO6/images/data-ver-arrow.png?fit=max\&auto=format\&n=2s8kQpg4kevldgO6\&q=85\&s=f9e2e7db3ccaf2f361ccf943bc75da6d) 4. Review the verification instructions. Do one of the following: 1. If the entity data is correct, select **Data is correct**, then click **Submit**. When prompted to confirm again, click **Yes**. 2. If the data is incorrect, select **Data is incorrect**. Enter the reason, then click **Submit**. > [!TIP] > > If there is more than one outstanding verification, they'll be listed sequentially by due date. Once all data verifications have been processed, the entity will display a `Verified` badge. ### The 'Verify entity' button isn't showing The **Verify entity** button only appears when you're eligible to verify that entity, and there's no tooltip or message when you aren't. If you expect to see it but don't, check the following: 1. The entity is in scope of a verification period. Confirm the entity matches the verification's **Entities to verify** settings on the **Entity verification settings** page. 2. The verification period is active. The button doesn't appear before the start date or after the end date. 3. You're a direct member of a team that owns the entity. Membership in a parent team, or ownership that reaches the entity through inheritance, doesn't make you eligible. 4. You have a required role, if the verification specifies one. Check **Team member roles responsible for verification** on the verification period, then confirm you hold that role on the owning team. 5. Your team's roles are populated. If team membership syncs from an identity provider, members may have no role assigned. See Verification and externally synced teams. ## Viewing verification statuses Entities that have been labeled as correct, incorrect, or are still pending review are listed on the **Data verification** page. Click into a verification to view its details. ## Flagging unverified entities via a Scorecard You can launch a Scorecard to automatically flag entities that have not been verified: 1. From the main sidebar, expand **Scorecards**, then expand **Scorecards**. 2. In the upper-right corner of the page, click **+Create Scorecard**. 3. Locate the **Entity Verification** template, then click **+Use**. 4. Make edits to the templated configuration if necessary, then click **Create Scorecard**. The Scorecard automatically evaluates your entities. If an entity has not been verified, the entity's owner will see a task appear on their Engineering homepage to let them know. ## Viewing incorrect entities via CQL report You can create a CQL report to view all entities that have been verified as incorrect through data verification. 1. From the main sidebar, expand **Tools**, then select **CQL reports**. 2. Locate the **Entity Verification Report** template, then click **+Use**. 3. Modify the report template as needed, then click **Create**. # GitOps settings Source: https://docs.cortex.io/configure/settings/gitops-settings Admins, or users with the `Configure settings` permission, can adjust system-wide settings for GitOps under [**Settings > GitOps**](https://app.getcortexapp.com/admin/settings/gitops). On this page, adjust settings that apply to entities, to [Scorecards](/standardize/scorecards), and to [Workflows](/streamline/workflows). To learn more about using a GitOps workflow for Cortex, see [Using GitOps for Cortex](/configure/gitops). ![See the GitOps settings under Settings > GitOps.](https://mintcdn.com/cortex-290c0c42/OnaYqLHqq-U_XM2R/images/gitops-settings.jpg?fit=max\&auto=format\&n=OnaYqLHqq-U_XM2R\&q=85\&s=2b7109e2c04877d3387badc70c08b99b) ## GitOps entities settings In the **Entities** tab of the GitOps Settings page, you can adjust settings that affect entities. ### Processing These settings allow you to control how Cortex processes and validates your GitOps-managed configuration, helping you ensure that only the desired files and changes are ingested and that errors are surfaced appropriately. * **Cortex YAML processing**: This setting enables or disables the processing of cortex.yaml files. If disabled, Cortex will not process these files for entity updates, but package and OpenAPI breaking change detections will still process. * **Process Cortex properties**: This setting controls whether Cortex processes the cortex-properties.yaml file after GitOps processing. If disabled, Cortex will ignore cortex-properties.yaml files. * **Package parsing during GitOps processing**: This setting determines if Cortex will parse package information (such as dependencies) during GitOps processing. If disabled, package parsing is skipped. * **OpenAPI detection**: This setting determines whether Cortex checks for breaking changes in API specs defined in cortex.yaml files. If disabled, Cortex does not check for these. ### Linter checks These options help you control the strictness and visibility of validation checks during your GitOps workflows, making it easier to catch and address configuration issues earlier. Note that these settings only apply if you are using GitHub in your GitOps workflow. * **Linter check on non-parsable files**: When disabled, GitOps processing will skip non-parsable entity YAML files in the repository. If you have errors in the processed YAMLs, the linter will fail regardless of this setting. * For example, if a YAML file is missing its `x-cortex-type` to define the entity type, that file would be considered non-parsable. * **GitOps linter check repository allowlist**: Choose which repositories to run the linter check on. If none are selected, the check will run on all repositories. * **Pull requests linter result for warning violations**: This option lets you choose whether the linter result for warning violations should result in success, neutral, or failure. This helps teams decide how strictly to enforce warnings in their CI/CD workflows. By default, if there are any errors in your YAML file, the linter will result with a failure. ![Adjust the linter check settings in Cortex.](https://mintcdn.com/cortex-290c0c42/4tRxSDOxhMkPeY0E/images/linter-check.jpg?fit=max\&auto=format\&n=4tRxSDOxhMkPeY0E\&q=85\&s=89d8cf3942f54a3306e1a9194dc63afc) ### Options by entity type These settings allow you to control whether each type of entity can be created or edited via the UI or whether they must be managed exclusively through GitOps. * **Enable UI editing for new entity types**: When enabled, entity editing can be done through the Cortex UI. When disabled, entities can only be edited through GitOps. * **Enable UI importing for new entity types**: When enabled, entities can be imported through the Cortex UI. When disabled, entities can only be created through GitOps. * **Entity GitOps repository allowlist for new entity types**: Choose which repositories to search for new entity types. If none are selected, Cortex will search all repositories. Below these toggle settings, you can choose to enable UI editing and UI importing per entity type, and you can select which repositories to search for each entity type. ![Adjust UI editing settings for entity types.](https://mintcdn.com/cortex-290c0c42/kiI3HgqRloEyGGgk/images/entity-gitops-options.jpg?fit=max\&auto=format\&n=kiI3HgqRloEyGGgk\&q=85\&s=3ff3abe13aad6762ec1a9785f1a4f950) ## GitOps Scorecard settings The GitOps Scorecard settings control how Scorecards are managed and edited in your workspace, allowing you to enforce a single source of truth and auditability for Scorecard changes. Learn more about GitOps for Scorecards in [Scorecards as code](/standardize/scorecards/scorecards-as-code). * **Enable GitOps for Scorecard editing**: When enabled, you can only edit Scorecards via GitOps, reagrdless of whether the Scorecard was originally created in the UI. * **Scorecard GitOps repository allowlist**: Choose which repositories to search for new Scorecard YAML files. If none are selected, Cortex will search all repositories. ![Choose whether to manage Scorecards in the UI or via GitOps.](https://mintcdn.com/cortex-290c0c42/TKBM5XkYAo_gc56V/images/scorecard-gitops-settings.jpg?fit=max\&auto=format\&n=TKBM5XkYAo_gc56V\&q=85\&s=4e38e552ccaf4c8b9104fde01b401bc9) ## GitOps Workflow settings The GitOps Workflow settings control how Workflows are managed and edited in your workspace, allowing you to enforce a single source of truth and auditability for Workflow changes. Learn more about GitOps for Workflows in [Workflows as code](/streamline/workflows/workflows-as-code). * **Enable GitOps for Workflows editing**: When enabled, you can only edit Workflows via GitOps. You can still create and delete Workflows in the Cortex UI. * **Workflow GitOps repository allowlist**: Choose which repositories to search for new Workflow YAML files. If none are selected, Cortex will search all repositories. ![Adjust settings to manage Workflows in the UI or via GitOps.](https://mintcdn.com/cortex-290c0c42/GdCQ7wvPeVXdjHh5/images/workflow-settings-gitops.jpg?fit=max\&auto=format\&n=GdCQ7wvPeVXdjHh5\&q=85\&s=038af391f148f5a8aa41f3c962c96317) # Adding an IP allowlist Source: https://docs.cortex.io/configure/settings/ip-allowlist An IP allowlist is a network security control that restricts access to your Cortex workspace based on the originating IP address of incoming requests. When enabled, only requests coming from IP addresses you've explicitly approved can reach your workspace; all others are blocked before they can authenticate. This adds a layer of defense beyond user credentials, ensuring that even if a password or session token is compromised, an attacker still cannot access your workspace from an unapproved network. IP allowlists are particularly useful for organizations that want to limit workspace access to trusted networks, such as a corporate office, a VPN, or a specific set of remote locations. You can specify individual IP addresses or entire ranges using [CIDR notation](https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing), giving you flexibility to cover anything from a single machine to an entire subnet. By default, the allowlist is empty and all IP addresses are permitted access. As soon as you add your first entry, the workspace automatically switches to a deny-by-default posture: only the addresses on the allowlist can connect, and all others are rejected. There's no separate toggle to enable enforcement, as the presence of any entry activates the restriction. **Before you begin** A few things to keep in mind before configuring your allowlist: * **Add your own IP address first.** The allowlist activates the moment you save your first entry, so omitting your current IP will lock you out of the workspace. Cortex warns you before this happens, but as a best practice, add your own IP to the list before saving. * **Account for all trusted networks.** Make sure you've identified every network your users connect from, including corporate offices, VPN exit nodes, remote workers' home networks, and any third-party services or integrations that make requests to your workspace. * **Plan for dynamic IPs.** Home internet connections and some cloud services use IP addresses that change over time. For these, use a CIDR range that covers the expected pool, or require users to connect through a VPN with a static egress IP. * **Include the remote MCP server if you use it.** If you use the [remote Cortex MCP](/get-started/cortex-ai-assistant/mcp/configuring-cortex-mcp#hosting-the-cortex-mcp-server-remotely), add the IP addresses the MCP server sends requests from, not the MCP server's own address. See [Allowlisting the remote MCP server](/get-started/cortex-ai-assistant/mcp/configuring-cortex-mcp#allowlisting-the-remote-mcp-server) for the addresses in each region. You can configure an IP allowlist in the Cortex UI or via the Cortex API. Your user or API key must have the `Configure IP Allowlist` permission to perform these steps. ## Configuring an IP allowlist via the Cortex UI Follow the steps below to configure an IP allowlist in Cortex. 1. From the main sidebar, click your avatar in the bottom-left corner. 2. Click **Settings**. 3. From the **Settings** menu, locate the **Security and access** section, then click **IP allowlist**. 4. In the upper-right corner, click **Add IP addresses**. 5. In the **Add IP addresses to allowlist side** panel, do one of the following: * Enter a single IP address 1. Under IP addresses, enter a single IP address. 2. Optionally, enter a description of the IP address. 3. Optionally, click **Add more** to add another IP address. 4. Click **Add addresses**. * Enter multiple IP addresses 1. Toggle on **Bulk edit**. 2. In the Entries field, enter or paste a list of IP addresses (and optional descriptions). 3. Click **Add addresses**. > [!WARNING] > > When you save the allowlist, Cortex checks whether your current IP is included. If it isn't, a warning appears before the change takes effect. This prevents you from accidentally locking yourself out of the workspace. ## Configuring an IP allowlist via the API See the [IP allowlist API documentation](/api/rest/ip-allowlist) to learn more about creating an allowlist through the API. You can retrieve a range of addresses, update existing addresses, and validate your IP addresses. Note that Cortex checks whether your IP address is included in the allowlist to prevent you from losing access to your workspace. ## Troubleshooting and FAQ **Why do I see a** `403 Forbidden IP address` **error when running a Workflow?** Workflow steps that call the Cortex API fail if the request originates from an IP that isn't on your allowlist. Send a message to [help@cortex.io](mailto:help@cortex.io) if you need further assistance. # Managing users and roles Source: https://docs.cortex.io/configure/settings/managing-users > **[Roles and permissions](/configure/settings/managing-users/permissioning)** > **[Configuring SSO for Cortex workspace logins](/configure/settings/managing-users/configuring-sso)** > **[Provisioning users with SCIM](/configure/settings/managing-users/scim/provisioning-users-with-scim)** > **[Configuring identity mappings](/configure/settings/managing-users/identity-mapping)** > **[Onboarding management](/configure/settings/managing-users/onboarding-mgmt)** # Configuring SSO for Cortex workspace logins Source: https://docs.cortex.io/configure/settings/managing-users/configuring-sso Cortex always maintains a strong security posture. Aside from being SOC 2 Type 2 certified and protecting your data through strict process and standards, Cortex supports SSO through most major vendors. SSO is supported through any OIDC provider. The scopes Cortex requires for OIDC to function are: `openid`, `email`, and `profile`, and the only data Cortex stores from the OIDC flow is the user's `name` and `email`. ### SSO integrations Cortex offers native integrations for: * [Entra ID](/configure/settings/managing-users/configuring-sso/entraid) (including [Entra ID SCIM](/configure/settings/managing-users/scim/entraid-scim)) * [Google](/configure/settings/managing-users/configuring-sso/google) * [Okta](/configure/settings/managing-users/configuring-sso/okta) (including [Okta SCIM](/configure/settings/managing-users/scim/okta-scim)) You can also configure other OIDC providers via the [Generic OIDC providers](/configure/settings/managing-users/configuring-sso/oidc) documentation. # Entra ID SSO Source: https://docs.cortex.io/configure/settings/managing-users/configuring-sso/entraid Cortex supports configuring Single Sign-On (SSO) with Microsoft Entra ID (formerly known as Azure Active Directory) with OpenID Connect for protecting access to your Cortex workspace. Cortex also supports an integration to track Entra ID teams and team members as entity owners as well as create Scorecards involving your Entra ID teams. See the [Entra ID integration page](/ingesting-data-into-cortex/integrations/entraid) for more information. ## Configuring Entra ID SSO for Cortex Users who have the `Configure OpenID Connector & SCIM` permission can configure Entra ID SSO for Cortex. ### Step 1: Setting up a new Entra ID application 1. Log in to the Microsoft Entra Admin Center at [https://entra.microsoft.com](https://entra.microsoft.com/). 2. From the left menu, select **Overview**. 3. Click **Add**, then select **App registration**. 4. In the **Name** field, enter a descriptive name for the application, e.g. `Cortex login`. 5. From the **Supported account types** drop-down menu, select **Single tenant only** / **Accounts in this organizational directory only.** Selecting this option means the SSO will only work for the given Entra ID instance—not for other organizations. 6. From the **Redirect URI (optional)** drop-down menu, select **Web**. 7. In the **Authorized redirect URI** field, enter `https://cortexapp.auth0.com/login/callback` . 8. Click **Register**. The app's overview page is displayed. 9. Copy the **Application (client) ID** value and store it in a secure location, as you will need this in the next steps. > [!NOTE] > > Refer to the Microsoft [quickstart guide](https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app#register-an-application) for more detailed instructions on setting up an Entra ID app. ### Step 2: Creating a client secret in Entra ID 1. Log in to the Microsoft Entra Admin Center at [https://entra.microsoft.com](https://entra.microsoft.com/). 2. From the left menu, select **App registrations**. 3. Select the **All applications** tab, then select your app. 4. Click **Add a certificate or secret.** 5. Select the **Client secrets** tab. 6. Click **New client secret**. 7. In the **Description** field, enter a description for the secret. 8. From the **Expires** drop-down menu, select an expiration. SSO stops working when the secret expires. Set an expiration that makes sense for your process. If you regularly rotate secrets, a shorter expiration period might make more sense. If you don't, a longer duration ensures that SSO continues to function without interruption. 9. Click **Add**. 10. Copy the value of the secret and store it in a secure location, as you will need this in the next steps. ### Step 3: Obtaining the metadata document endpoint in Entra ID 1. Log in to the Microsoft Entra Admin Center at [https://entra.microsoft.com](https://entra.microsoft.com/). 2. From the left menu, select **App registrations**. 3. Select the **All applications** tab, then select your app. 4. Select the **Endpoints** tab. 5. Copy the **OpenID Connect metadata document** up to `/v2.0` . It should be in the format `https://login.microsoftonline.com//v2.0`. ### Step 4: Configuring SSO in Cortex 1. Log in to Cortex. 2. From the main sidebar, click your avatar in the bottom-left corner. 3. Click **Settings**. 4. From the **Settings** menu, scroll to the **Security and access** section, then select **OpenID connector**. 5. Configure the form: * From the **Type** drop-down menu**,** select **Azure**. * Below **Identifier**, **e**nter your client ID. * Below **Secret**, enter your client secret. * Below **Issuer**, enter the issuer URI. * Do **not** include a backslash after `v2.0` in the issuer URI! This will process as an invalid configuration for the URI. 6. Click **Save**. Once saved, users will only be able to sign in to Cortex using their Entra ID account. # Google SSO Source: https://docs.cortex.io/configure/settings/managing-users/configuring-sso/google By default, Cortex uses Google as the Single Sign-On (SSO) authentication provider. Follow the instructions on this page to configure your own Google Cloud app for SSO to your Cortex workspace. Cortex also supports an integration to track Google teams and team members as entity owners, pull in Service Level Objectives (SLOs) from Google Cloud Observability, and create Scorecards involving your Google resources and teams. See the [Google integration page](/ingesting-data-into-cortex/integrations/google) for more information. ## How to configure Google SSO for Cortex You must have the `Configure OpenID Connector & SCIM` permission. ### Step 1: Set up a Google OAuth app To set up a new Google OAuth app, follow [Google's OpenID Connect instructions](https://developers.google.com/identity/openid-connect/openid-connect). ### Step 2: Create an OAuth client ID in Google Cloud 1. In your Google Cloud instance, navigate to **APIs & Services**. 2. Click **Create Credentials**. Under Application type, select **Web application** 3. In the **Authorized redirect URI section**, add `https://cortexapp.auth0.com/login/callback` as an authorized [redirect URI](https://developers.google.com/identity/openid-connect/openid-connect#setredirecturi). 4. Click **Create**. * You will be redirected to the APIs & Services page. A modal will open with the client ID and secret. 5. Copy the client ID and client secret. Store these in a secure location, as you will need them in the next steps. ### Step 3: Configure SSO in Cortex 1. In your Cortex workspace, navigate to [**Settings > OpenID Connector**](https://app.getcortexapp.com/admin/settings/oidc). 2. Configure the form: * **Type**: Select `Google`. * **Identifier:** Enter the client ID from Step 2. * **Secret:** Enter the client secret from Step 2. * **Issuer:** Enter `https://accounts.google.com`. 3. At the bottom of the page, click **Save**. After saving your configuration, users will only have the option to sign in to your Cortex workspace via your Google Cloud account. # Other OIDC SSO providers Source: https://docs.cortex.io/configure/settings/managing-users/configuring-sso/oidc This guide explains how to configure Single Sign-On (SSO) for your Cortex instance with OpenID Connect (OIDC) providers that are not available as native integrations. You must have the `Configure OpenID Connector & SCIM` permission. ### Step 1: Configure your provider In your OIDC provider, before setting up SSO with a third-party application, you will need to configure: * An application and permissions * The Cortex redirect URI: `https://cortexapp.auth0.com/login/callback` * A client ID and client secret See your provider's documentation for instructions. ### Step 2: Configure SSO in Cortex 1. In Cortex, navigate to the [OIDC settings page](https://app.getcortexapp.com/admin/settings/oidc). 2. Configure the OIDC settings: * **Type**: Click the dropdown and type in the name of the OIDC provider. In the dropdown, click **+Add**. * **Identifier**: Enter your OIDC provider client ID. * **Secret**: Enter your OIDC provider client secret. * **Issuer**: Enter the auth URL from your SSO provider, e.g., `https://oauth.id.jumpcloud.com/` 3. Click **Save**. ### Troubleshooting and FAQ See frequently asked questions below. > **I'm receiving a 'No verified email found' error.** > > This error occurs when Cortex cannot find a valid email address in the ID token returned by your OIDC provider. To resolve: > > 1. Ensure the `email` scope is requested. Your OIDC application must include the `email` scope (in addition to `openid` and `profile`) so the provider includes email claims in the token. > 2. Ensure the `email` claim is mapped. In your OIDC provider's attribute/claim mappings, verify that the `email` claim is included in the ID token. Some providers do not include it by default. > 3. Include `email_verified`. Some providers omit the `email_verified` claim, which can cause Cortex to reject the email. Add `email_verified` (set to `true`) as a claim in your provider's token configuration. # Okta SSO Source: https://docs.cortex.io/configure/settings/managing-users/configuring-sso/okta Cortex supports configuring Single Sign-On (SSO) with Okta to protect access to your Cortex workspace. Additionally, you can configure [Okta SCIM with Cortex](/configure/settings/managing-users/scim/okta-scim). Cortex also supports an integration to track Okta teams and team members as entity owners as well as create Scorecards involving your Okta teams. See the [Okta integration page](/ingesting-data-into-cortex/integrations/okta) for more information. ## Configuring Okta SSO for Cortex Users with the `Configure OpenID Connector & SCIM` permission can configure Okta SSO in Cortex. There are two options to configure Okta SSO: * Installing the [Cortex app in the Okta Integration Network (OIN)](https://www.okta.com/integrations/cortex/) * This option provides a simplified setup for most standard use cases. It's compatible with [Okta SCIM](/configure/settings/managing-users/scim/okta-scim) provisioning features. * Creating your own app * This option is best if you need more flexibility in configuring redirect behavior, want to configure automatic sign-on, or if you require multiple or advanced configurations. ### Configuring Okta SSO via the Cortex OIN app #### Step 1: Installing the Cortex OIN app Cortex's OIN app configures the initial steps for Okta SSO. 1. Install the Cortex app from the [Okta OIN](https://www.okta.com/integrations/cortex/). > [!NOTE] > > You can also access the Cortex app from your Okta instance by navigating to **Applications** and selecting Cortex from the *App Integration Catalog*. #### Step 2: Copying the client ID and client secret 1. In Okta, navigate to the **Applications** page and select the Cortex app from your list of applications. 2. Click the **Sign On** tab. 3. Copy the values of the client ID and client secret. Store them in a secure location, as you will need these in the next steps. > [!NOTE] > > Be sure to copy the client ID and the client secret and save them for later. Do not skip this step—you can only view these values once! #### Step 3: Obtaining the issuer URI In Okta, each authorization server has a unique issuer URI. See [Okta's instructions](https://developer.okta.com/docs/concepts/auth-servers/) for information on finding your Okta issuer URI. It should look like `https://{okta-domain}.okta.com`. #### Step 4: Configuring SSO in Cortex 1. Log in to Cortex. 2. From the main sidebar, click your avatar in the bottom-left corner. 3. Click **Settings**. 4. From the **Settings** menu, scroll to the **Security and access** section, then select **OpenID connector**. The **OpenID connector** page is displayed. 5. Enter the following values: * From the **Type** drop-down menu, select **Okta**. * In the **Identifier** field, enter your client ID. * In the **Secret** field, enter your client secret. * In the **Issuer** field, enter the issuer URI. 6. Click **Save**. Once saved, users will only be able to sign in to Cortex using their Okta account. ### Configuring Okta SSO via your own app #### Step 1: Creating an Okta app integration 1. Log in to the Okta admin console. 2. Navigate to **Applications**, then select **Create App Integration**. 3. In the modal under the sign-in methods, select **OIDC - Open ID Connect**. Under **Application type**, select **Web Application**. 4. On the next page, enter a name, logo, and grant type for the app. * To bypass the login screen and enable automatic sign on, see [Auto sign-on](/configure/settings/managing-users/configuring-sso/okta#auto-sign-on) below. 5. Click **Save**. * You will be redirected to the app's overview page. 6. From the app's overview, click the **General** tab. Copy the values of the client ID and client secret. Store these in a secure location, as you will need them in the next steps. **Auto sign-on** You can bypass the login screen and enable automatic sign-on with the following configurations for your Okta app: * **Grant type** - Authorization Code * **Initiate login URI** - `https://app.getcortexapp.com/login?tenantCode=TENANT_CODE` (replace `TENANT_CODE` with your Cortex tenant code. This is what triggers auto sign-on directly into your workspace) * **Sign-in redirect URIs** - Add all of the following: * `https://cortexapp.auth0.com/login/callback` (required for all configurations; this is the redirect URI the Auth0 OAuth flow uses) * `https://api.getcortexapp.com/login/oauth2/code/okta` (required for the standard SSO login flow) * `https://app.getcortexapp.com/login?tenantCode=TENANT_CODE` (replace `TENANT_CODE` with your Cortex tenant code) #### Step 2: Configuring SSO in Cortex 1. Log in to Cortex. 2. From the main sidebar, click your avatar in the bottom-left corner. 3. Click **Settings**. 4. From the **Settings** menu, scroll to the **Security and access** section, then select **OpenID connector**. The **OpenID connector** page is displayed. 5. Enter the following values: * From the **Type** drop-down menu, select **Okta**. * In the **Identifier** field, enter your client ID. * In the **Secret** field, enter your client secret. * In the **Issuer** field, enter your Okta account domain, e.g. `https://{okta-domain}.okta.com`. 6. Click **Save**. Once saved, users will only be able to sign in to Cortex using their Okta account. ## Troubleshooting and FAQ See frequently asked questions below. > **I see authentication failures and/or can't to connect to Okta** > > Follow these steps: > > 1. Check your network connectivity from Cortex to Okta endpoints. > 2. Verify no firewall rules or network changes are blocking outbound traffic. > 3. Confirm required Okta domains/endpoints are reachable. > **I see TLS handshake failures in the logs / The TLS handshake could not complete, blocking the authentication flow** > > Follow these steps: > > 1. Validate that outbound HTTPS (port 443) is allowed. > 2. Check for SSL/TLS inspection or proxy interference. > 3. Confirm certificates are not blocked or altered. # Configuring identity mappings Source: https://docs.cortex.io/configure/settings/managing-users/identity-mapping The identity mappings feature allows you to map accounts from different integrations to Cortex accounts, based on name or email address. With identity mapping, you can not only make sure that integrations are working properly for your team members, but you can also ensure that the [Developer Homepage](/streamline/homepage) and [Eng Intelligence](/improve/eng-intelligence) features are working as intended with their mappings. In most cases, Cortex can automatically match user identities across systems with no setup required. When account details differ across tools, Cortex Admins can manually review and map users in **Settings > Identity mappings**. Identity mapping is available for: * [Azure DevOps](/ingesting-data-into-cortex/integrations/azuredevops) * [Bitbucket](/ingesting-data-into-cortex/integrations/bitbucket) * [ClickUp](/ingesting-data-into-cortex/integrations/clickup) * [GitHub](/ingesting-data-into-cortex/integrations/github) * [GitLab](/ingesting-data-into-cortex/integrations/gitlab) * [Jira](/ingesting-data-into-cortex/integrations/jira) * [Microsoft Teams](/ingesting-data-into-cortex/integrations/microsoftteams) * [Opsgenie](/ingesting-data-into-cortex/integrations/opsgenie) * [PagerDuty](/ingesting-data-into-cortex/integrations/pagerduty) * [Slack](/ingesting-data-into-cortex/integrations/slack) Git providers and Jira support [multiple mappings per user](/configure/settings/managing-users/identity-mapping#mapping-multiple-identities-to-users). ## View your personal identity mappings All of your personal mappings for your established integrations are listed in Cortex under [**Settings > My identity mapping**](https://app.getcortexapp.com/admin/settings/my-integration-accounts). From this page, you can directly add your OAuth user for GitHub cloud if there’s no mapping. For other integrations, a user with the `Configure identity mappings` permission must configure the identity mappings. > [!WARNING] > > OAuth mapping is only valid for GitHub cloud and not for GitHub Enterprise server. ## Viewing and managing all identity mappings Users with the `Configure Identity Mappings` permission can review all user mappings specific to each configured integration. Every integration you've set up appears on this page, whether or not you've mapped users to it yet. **To access**: 1. From the main sidebar, click your avatar in the bottom-left corner. 2. Select **Settings**. 3. Scroll to the **Identity mappings section**.\ ![](https://mintcdn.com/cortex-290c0c42/kB9I5hpwwMkz0yx1/images/identity-mappings.png?fit=max\&auto=format\&n=kB9I5hpwwMkz0yx1\&q=85\&s=6c5ca30de2388dcc397531ec0aeb7439) ### Reviewing mapped and unmapped users 1. From the main sidebar, click your avatar in the bottom-left corner. 2. Select **Settings**. 3. Scroll to the **Identity mappings section**. 4. Select the integration whose users you want to review. 5. In the upper-right corner of the integration's **User mappings** page, click **Display**.\ ![](https://mintcdn.com/cortex-290c0c42/fKqTUx7McPYDap8G/images/review-mapped-users.png?fit=max\&auto=format\&n=fKqTUx7McPYDap8G\&q=85\&s=d0268c37ccece6f72904d5475dd48d36) 6. Toggle on or off the following: * **Active integrations only** (toggled on by default) - Show mappings only for integration configurations that are currently installed. Uninstalling a configuration doesn't delete the mappings you've saved for it; toggle this setting off to see them again. * **Hide mapped users** - Show only the users who don't have a mapping yet. 7. Click **Done**. #### Mapping unmapped users While viewing the user mappings for an integration, you can view Cortex's suggestions for user accounts. You can accept suggestions individually by clicking the checkmark next to a suggestion in a user’s row: ![](https://mintcdn.com/cortex-290c0c42/HbTtnyKVq-sSUnnp/images/map-unmapped.png?fit=max\&auto=format\&n=HbTtnyKVq-sSUnnp\&q=85\&s=38460d9cf4f2bfabf673e71415bb5065) To accept multiple suggestions at once, click **Accept all suggestions** at the top of the list. This opens a dialog listing every account that has a suggested mapping, so you can review the suggestions and confirm them for many users at once. ![](https://mintcdn.com/cortex-290c0c42/HbTtnyKVq-sSUnnp/images/mapping-bulk.png?fit=max\&auto=format\&n=HbTtnyKVq-sSUnnp\&q=85\&s=b3390e497def3abe85aeb42871f35b91) If Cortex doesn't have a suggestion, select a mapping for that user from the **Select mapping** drop-down. ### Mapping multiple identities to users Cortex supports more than one identity per user, so if you run multiple instances of a Git provider or Jira, you can map an identity for each instance alias. The following providers are supported: * [Azure DevOps](/ingesting-data-into-cortex/integrations/azuredevops) * [Bitbucket](/ingesting-data-into-cortex/integrations/bitbucket) * [GitHub](/ingesting-data-into-cortex/integrations/github) * [GitLab](/ingesting-data-into-cortex/integrations/gitlab) * [Jira](/ingesting-data-into-cortex/integrations/jira) **To configure multiple mappings for a user**: 1. From the main sidebar, click your avatar in the bottom-left corner. 2. Select **Settings**. 3. Scroll to the **Identity mappings section**. 4. Select the integration whose users you want to map. 5. Locate the user, then click the arrow next to their name to expand their mappings. 6. If an identity isn't mapped yet, the dropdown next to the instance alias suggests a user. Select the user, then click **Save**. * When a mapping isn't associated with an alias, the **Identity mappings** settings show a dropdown labeled **Unknown**. This can happen when an integration has multiple aliases configured. The next time Cortex syncs user identity information, it tries to match the mapping to an alias. The **Unknown** label doesn't affect how Cortex works. * Cortex lists only the aliases for integration configurations that are currently installed. If an alias you expect is missing from a user's mappings, the configuration it belongs to may have been removed or renamed. Uninstalling a configuration doesn't delete the mappings you've saved for it. To see them, click **Display** at the top of the list, then toggle off **Active integrations only**. ![](https://mintcdn.com/cortex-290c0c42/GdCQ7wvPeVXdjHh5/images/unmapped-users.jpg?fit=max\&auto=format\&n=GdCQ7wvPeVXdjHh5\&q=85\&s=bdff155a75e8cb82e010e23f755772c8) # Onboarding management Source: https://docs.cortex.io/configure/settings/managing-users/onboarding-mgmt The Onboarding management tool allows you to stay informed about onboarding status for users in Cortex. Users with the `View Onboarding management` permission can see the onboarding management tool. Users with the `Enable Onboarding management` permission can message users directly from this page to remind them to complete onboarding for logging in to your organization's Cortex instance. ## View onboarding management To access onboarding management, navigate to **Tools > Onboarding**. Here you can view a list of teams and the number of team members who have onboarded. The tool also includes a progress bar so you can see the overall percentage of users who have been onboarded. ![onboarding 1](https://mintcdn.com/cortex-290c0c42/wjT-J8PNs9MwpcFs/images/onboarding-mgmt.jpg?fit=max\&auto=format\&n=wjT-J8PNs9MwpcFs\&q=85\&s=8f7c1525eb36ac5686b9bc487bb67d54) ### Onboarding statuses Users will have one of four different statuses on this page: * `Not connected`: Does not have their identity mapped from an external account. * `Notified`: Has been sent a message for onboarding. * `Connected`: Has identity mapped from an external account and can receive notifications about the onboarding process, but has not yet logged in to Cortex. * `Onboarded`: Has completed onboarding. #### Connecting a user with a "Not connected" status If a user's onboarding status is `Not connected`, users with the `Configure identity mappings` permission can map the user's identity to an external account: * Slack: Navigate to the [Slack Identity mappings page](https://app.getcortexapp.com/admin/settings/slack-mappings) in your Cortex settings. * Microsoft Teams: Navigate to the [Microsoft Teams identity mappings page](https://app.getcortexapp.com/admin/settings/microsoftteams-mappings) in your Cortex settings. From this identity mapping page, you can select a mapping from the dropdown menu for each user, as well as see and edit mapped users. ### Message users who have not onboarded On this page, you can message team members who haven’t onboarded. The supported messaging methods are Slack and Microsoft Teams. You must have the `Enable Onboarding management` permission to message users on this page. 1. On the onboarding management page, in the row displaying the user, click **Message user**: ![](https://mintcdn.com/cortex-290c0c42/wjT-J8PNs9MwpcFs/images/onboard-message.jpg?fit=max\&auto=format\&n=wjT-J8PNs9MwpcFs\&q=85\&s=ba88aaed84b3d41c9aa4c30076ccad60) 2. Optionally include a custom message, and review the message preview on the right side of the modal. 3. Click **Send message**. ### Message teams who have not onboarded If multiple members of the same team have not completed onboarding, you can message the team. You must have the `Enable Onboarding management` permission to message users on this page. 1. In the row for the team, click **Message team**. * In the modal, expand "Message details" to view which users the message will be sent to. 2. Optionally include a custom message, and review the message preview on the right side of the modal. 3. Click **Send message**. # Roles and permissions Source: https://docs.cortex.io/configure/settings/managing-users/permissioning Users and teams in Cortex can be assigned to a role which permits or limits the ability to perform specific actions within Cortex. These actions range from creating API keys and adding integrations to editing Scorecards and creating entities. Roles allow you to ensure that only authorized individuals can make high-level changes to your workspace. You can use the [default roles](/configure/settings/managing-users/permissioning#default-roles) or you can [create custom roles](/configure/settings/managing-users/permissioning#custom-roles). If a user is assigned to more than one role, they will retain the permissions of the least restricted assigned role. For example, if a user is assigned a `Manager` role and they are a member of a team assigned the `Admin` role, then they will have admin permissions throughout Cortex. Using custom roles may introduce other permissions that supersede default roles. If a user does not have permission to perform an action, the option will not appear for them. ## Roles in Cortex ### Default roles When you first access your Cortex account, the following roles are available by default: * **Admins:** Admins are the owners of the workspace. They have global access to everything within Cortex: settings, Scorecards, and entities. * **Managers:** Managers have most of the same abilities as admins, but cannot modify permissions or other settings. Managers can create and edit Scorecards, entities, and teams. * **Users:** Users cannot modify settings, nor can they edit or create Scorecards. Users can edit and create entities and teams. * **Viewers:** Viewers cannot create or edit anything within the workspace. This is a read-only role. The following table shows which permissions are associated with the default user roles in Cortex. Note that you can add each of these permissions to [custom roles](/configure/settings/managing-users/permissioning#custom-roles). | Permission | Viewer | User | Manager | Admin | | - | :-: | :-: | :-: | :-: | | View CQL reports | ✓ | ✓ | ✓ | ✓ | | View initiatives | ✓ | ✓ | ✓ | ✓ | | View onboarding management | ✓ | ✓ | ✓ | ✓ | | View Scorecards | ✓ | ✓ | ✓ | ✓ | | View catalogs | ✓ | ✓ | ✓ | ✓ | | Edit and create entities | | ✓ | ✓ | ✓ | | Archive and delete entities | | ✓ | ✓ | ✓ | | Edit and create entity types | | ✓ | ✓ | ✓ | | Edit CQL reports | | ✓ | ✓ | ✓ | | Edit initiatives | | ✓ | ✓ | ✓ | | Configure Scaffolder templates | | ✓ | ✓ | ✓ | | Run the Scaffolder | | ✓ | ✓ | ✓ | | Run query builder | | ✓ | ✓ | ✓ | | View GitOps logs | | ✓ | ✓ | ✓ | | View Workflows | | ✓ | ✓ | ✓ | | View Workflow runs | | ✓ | ✓ | ✓ | | Execute Workflow runs | | ✓ | ✓ | ✓ | | View Scorecard exemptions | | ✓ | ✓ | ✓ | | View Eng Intelligence | | | ✓ | ✓ | | Configure Eng Intelligence custom metrics | | | ✓ | ✓ | | Configure Eng Intelligence | | | ✓ | ✓ | | View Eng Intelligence user dimensions | | | ✓ | ✓ | | Configure identity mappings | | | ✓ | ✓ | | Edit and create Scorecards | | | ✓ | ✓ | | Edit, create, and delete catalogs | | | ✓ | ✓ | | Edit Eng Intelligence custom metric data | | | ✓ | ✓ | | Edit OpEx comments | | | ✓ | ✓ | | Edit Workflows | | | ✓ | ✓ | | Run re-evaluation of Scorecards | | | ✓ | ✓ | | View audit logs | | | | ✓ | | View breaking API changes | | | | ✓ | | View notification logs | | | | ✓ | | View roles | | | | ✓ | | Configure appearance | | | | ✓ | | Configure catalog | | | | ✓ | | Configure custom metrics | | | | ✓ | | Configure discovery audit events | | | | ✓ | | Configure entity verification periods | | | | ✓ | | Configure integrations | | | | ✓ | | Configure notifications | | | | ✓ | | Configure plugin appearance | | | | ✓ | | Configure Scorecard exemptions | | | | ✓ | | Edit, create, and delete API keys | | | | ✓ | | Edit custom metric data | | | | ✓ | | Edit initiatives | | | | ✓ | | Edit plugins | | | | ✓ | | Edit plugin proxies | | | | ✓ | | Edit, create, and delete secrets | | | | ✓ | | Enable entity dependency discovery | | | | ✓ | | Enable onboarding management | | | | ✓ | | Execute notification logs | | | | ✓ | | Configure IP allowlist | | | | ✓ | | Configure OpenID Connector and SCIM | | | | ✓ | | Configure roles | | | | ✓ | | Configure settings | | | | ✓ | | Run query builder with third-party integrations[^1] | | | | ✓ | ### Custom roles Cortex gives you the ability to create custom roles with granular permissions so users have the access they need. Learn more in the [Custom Roles documentation](/configure/settings/managing-users/permissioning/custom-roles). ### Permissioning in Workflows In addition to the granular permissions listed on this page that apply to [Workflows](/streamline/workflows), it is also possible to: * Configure specific users, teams, or roles who are allowed to run a Workflow * Require a user to be an Owner or Editor of an entity in order to run a workflow These configurations are described in more detail in the [Workflow documentation](/streamline/workflows/configuring-workflow-settings) under "Step 2: Configure your Workflow settings." ## Viewing and assigning roles ### View roles In [**Settings > Roles and permissions**](https://app.getcortexapp.com/admin/settings/permissions) in Cortex, users with the Admin role can view a list of all users in the workspace and their assigned roles. On this page, you can also assign roles and create custom roles. ![](https://mintcdn.com/cortex-290c0c42/GdCQ7wvPeVXdjHh5/images/user-management.jpg?fit=max\&auto=format\&n=GdCQ7wvPeVXdjHh5\&q=85\&s=8d0aed8549fc66e45254a12f31caa743) ### Filter the list ![](https://mintlify.s3.us-west-1.amazonaws.com/cortex-290c0c42/images/filter-users%20%281%29.jpg) * To filter the list by role, click **Filter** in the upper right corner of the user list, then select and apply filters. * To filter the list by user, click the magnifying glass icon in the upper right corner of the list, then type in a name. ### Assigning a role to a user Users with the `Edit Roles` permission can change the roles assigned to a user. From the **Edit user roles** side panel, you can add roles, remove a single role, or remove all of a user's roles at once. > [!NOTE] > > Every user must have at least one role assigned. If you remove all of a user's roles, add at least one role back before you save. 1. From the main sidebar, click your avatar in the bottom-left corner. 2. Click **Settings**. 3. From the **Settings** menu, locate the **Security and access** section, then click **Permissions**. 4. From the **Users** tab, locate the user, then click the **pencil icon** next to their name. 5. In the side panel, do any of the following: * To add a role, select one or more roles from the dropdown. * To remove a single role, click **Remove** next to that role. * To remove every role at once, click **Remove all**. 6. Click **Save changes**. Your changes apply as soon as you save. You don't need to reselect the roles you want to keep. #### Assigning roles to multiple users 1. From the main sidebar, click your avatar in the bottom-left corner. 2. Click **Settings**. 3. From the **Settings** menu, locate the **Security and access** section, then click **Permissions**. 4. From the **Users** tab, select the checkboxes next to the users you want to assign a role to. 5. In the box that appears near the bottom of the list, click **Roles**, then select **Add roles**. 6. In the side panel, do one of the following: * To give every selected user an additional role, select **Add to existing roles**, then select the roles from the **Roles to be added** dropdown. * To overwrite the roles for every selected user, select **Replace existing roles**, then select their new roles from the dropdown. 7. Click **Add and save**. > [!NOTE] > > Removing a single role isn't supported for bulk edits, because the same role may not apply to every selected user. To take one role away from several users, edit each user individually, or use **Replace existing roles** and select only the roles they should keep. ### Assigning a role to a team Users with the `Edit Roles` permission can change the roles assigned to a team. Team roles allow you to assign the team permissions to a set of users all at once. When you add a new member to a team, Cortex automatically assigns the team role to them. 1. From the main sidebar, click your avatar in the bottom-left corner. 2. Click **Settings**. 3. From the **Settings** menu, locate the **Security and access** section, then click **Permissions**. 4. From the **Teams** tab, locate the team, then click the **pencil icon** next to its name. 5. In the side panel, do any of the following: * To add a role, select one or more roles from the dropdown. * To remove a single role, click **Remove** next to that role. * To remove every role at once, click **Remove all**. 6. Click **Save changes**. Your changes apply as soon as you save. You don't need to reselect the roles you want to keep. #### Assigning roles to multiple teams 1. From the main sidebar, click your avatar in the bottom-left corner. 2. Click **Settings**. 3. From the **Settings** menu, locate the **Security and access** section, then click **Permissions**. 4. From the **Teams** tab, select the checkboxes next to the teams you want to assign a role to. 5. In the box that appears near the bottom of the list, click **Roles**, then select **Add roles**. 6. In the side panel, do one of the following: * To give every selected team an additional role, select **Add to existing roles**, then select the roles from the **Team roles** dropdown. * To overwrite the roles for every selected team, select **Replace existing roles**, then select their new roles from the dropdown. 7. Click **Add and save**. ## Adding and removing Cortex users ### Review users At the top of the [Roles and permissions settings page](https://app.getcortexapp.com/admin/settings/permissions), you can see the total number of seats, the number of users who have logged in to your instance, the number of users who have only received notifications but have not logged in, and the number of available seats remaining. You can also view this information in the [About page](https://app.getcortexapp.com/admin/settings/about) under Workspace settings. ### Set a default role for new users To set a default role for all new users provisioned for your workspace: 1. At the top of the [Roles and permissions settings page](https://app.getcortexapp.com/admin/settings/permissions), click into the field under "Default roles." 2. Select the desired role. ### Add a user To add a new user to the platform, first direct the user to attempt to log in to your organization's Cortex account. If the user has the appropriate email domain, they will be added automatically upon login. If the user sees an "access denied" error, this indicates that the user is not authorized to access the app via your SSO tool. #### **Add a secondary domain** Cloud customers who need to add a secondary email domain should contact [help@cortex.io](mailto:help@cortex.io) for assistance. This restriction does not apply to self-hosted customers. ### Remove a user To delete a user: 1. In the list of User permissions, locate the user you need to delete. 2. Click the trash icon for the user. ![](https://mintlify.s3.us-west-1.amazonaws.com/cortex-290c0c42/images/delete-user%20%281%29.jpg) 3. In the confirmation modal, click **Delete**. #### What is retained When a user is deleted, all data created by the user — such as Scorecards, custom entities, Workflows, and other configuration — will remain in Cortex and continue to function normally. However, any personal access tokens created by the user will be permanently removed. > [!WARNING] > > If any integrations or automation scripts depend on a deleted user's personal access token, they will stop working. Update those integrations to use a different token before deleting the user. #### Ownership and team membership Deleting a Cortex user only removes their ability to log in and their personal access tokens. It does **not** automatically remove their email from: * **Entity ownership fields** — such as service owners or business owners defined in the Cortex UI or via `x-cortex-owners` in YAML * **Team membership** — defined in the Cortex UI, YAML, or synced from external systems (e.g., GitHub, PagerDuty, Opsgenie) * **Notification targets** — any notification rules, Workflow steps, or on-call references that use the user's email Ownership and team membership are stored independently from user accounts. To fully remove a deleted user as an owner or team member, you must update those fields separately — either in the Cortex UI, in your YAML definitions, or in the external system that syncs that data. #### Visibility of deleted users on teams Depending on your workspace configuration, deleted users may or may not remain visible on Team pages after their account is removed. Team membership is stored separately from user accounts and can be controlled by workspace-level settings. > [!NOTE] > > Contact [Cortex Support](mailto:help@cortex.io) if you need deleted users to remain visible on teams for ownership tracking purposes. #### Reactivation If a deleted user later regains access to your identity provider (for example, Okta or Google) and logs back into Cortex with the same email address, a **new** Cortex user account will be created. They will be assigned the workspace's default role. Any ownership or team membership that still references their email will continue to be associated with them automatically — no manual re-linking is required. If an individual has left your organization entirely and is no longer a user in your identity provider, they will not be able to regain access to your organization's Cortex account. [^1]: This permission is scoped to admins by default to avoid issues with rate limiting, but it can be added to a custom role. # Custom roles Source: https://docs.cortex.io/configure/settings/managing-users/permissioning/custom-roles ## Overview In Cortex, there are [four default roles](/configure/settings/managing-users/permissioning#default-roles): Viewer, User, Manager, and Admin. While each of these provides access to different Cortex features, you can also create custom roles to give users more granular permissions. ## Creating custom roles ### How to create a custom role 1. In Cortex, go to the [Roles and permissions settings page](https://app.getcortexapp.com/admin/settings/permissions). 1. Click your avatar in the lower left corner, then click **Settings**. 2. Under "Authentication and access," click **Roles and permissions**. 2. In the upper right corner, click **Create custom role**. ![The "Create custom role" button is on the right side](https://mintlify.s3.us-west-1.amazonaws.com/cortex-290c0c42/images/create-custom-role%20%281%29.jpg) 3. In the "Create custom role" modal, fill in the basic information: * **Role name**: Enter a name for the role. * **Identifier**: This field is automatically populated based on the role name. It is a unique identifier for the role, made of letters, digits, and hyphens. * **Description**: Optionally, add a description of the role to help others understand its purpose. * **Settings**: Expand each of the Permission sections to view and toggle on/off a permission setting for the role. All permissions are toggled off by default. ![](https://mintlify.s3.us-west-1.amazonaws.com/cortex-290c0c42/images/create-custom-role%20%282%29.jpg) 4. Click **Create role**. ### Assign a custom role You can assign a custom role to a team or user the same way you would assign a default role. See [Assigning a role to a user](/configure/settings/managing-users/permissioning#assigning-a-role-to-a-user) for instructions. It is possible to assign multiple roles to an individual user or team. When multiple roles are assigned, the resulting permissions will be the maximum permissions associated with their assigned role(s). For example, if an individual is assigned two roles with distinct set of permissions, all of those permissions will be applied to that user. ### Set a custom role as default for new users For information on creating or deleting users and setting a default role for new users, see [Adding and removing Cortex users](/configure/settings/managing-users/permissioning#adding-and-removing-cortex-users). ### Delete a custom role To delete a custom role: 1. On the [Roles and permissions settings page](https://app.getcortexapp.com/admin/settings/permissions), click the **User role** tab. 2. Click the trash icon next to a role. ![](https://mintcdn.com/cortex-290c0c42/WknxdPOUKwxfFHMJ/images/delete-custom-role.jpg?fit=max\&auto=format\&n=WknxdPOUKwxfFHMJ\&q=85\&s=a175d59f9ae55a692a749f336d44b44b) 3. In the confirmation modal, click **Delete**. Note that you cannot delete a custom role if it is associated with a [plugin](/streamline/plugins). ### Available permissions for custom roles The table below describes the permission options you can add to a custom role. | Category | Permission | Description | | - | - | - | | Catalogs | **Catalogs view** | View catalogs and entities | | Catalogs | **Entity types edit** | Create, edit, and delete entity types | | Catalogs | **Catalogs edit** | Create, edit, and delete catalogs | | Catalogs | **Entities edit** | Create, edit, and delete entities | | Catalogs | **Entities archive** | Archive entities | | Catalogs | **Entities delete** | Delete entities | | Catalogs | **Entity dependency discovery enable** | Sync dependencies directly when on the dependency graph feature | | Catalogs | **Entity verification period configure** | Create and edit periods for verifying Cortex entities | | Scorecards & Initiatives | **Scorecards view** | View scorecards | | Scorecards & Initiatives | **Scorecards edit** | Create, edit, and delete scorecards | | Scorecards & Initiatives | **Scorecards re-evaluation execute** | Manually trigger a scorecard's evaluation via the UI | | Scorecards & Initiatives | **Scorecard exemptions view** | View scorecard exemptions | | Scorecards & Initiatives | **Scorecard exemptions configure** | Approve or revoke scorecard exemptions | | Scorecards & Initiatives | **Initiatives view** | View initiatives | | Scorecards & Initiatives | **Initiatives edit** | Create, edit, and delete initiatives | | Reporting | **Scorecard report view** | View scorecard reports | | Reporting | **CQL report view** | Ability to view CQL reports | | Reporting | **CQL report edit** | Create, edit, and delete CQL reports | | Eng Intelligence | **Eng Intelligence view** | View Eng Intelligence metrics. Viewing data by individual users also requires **View Eng Intelligence User Dimensions** | | Eng Intelligence | **Eng Intelligence configure** | Configure Eng Intelligence settings | | Eng Intelligence | **View Eng Intelligence User Dimensions** | Filter, group, and export Eng Intelligence data by individual users, such as PR authors and reviewers, deployers, assignees, and entity owners | | Eng Intelligence | **Custom Metrics configure** | Create, edit, and delete Eng Intelligence custom metrics | | Eng Intelligence | **Custom Metric data edit** | Create, edit, and delete Eng Intelligence custom metrics data points via API | | Workflows | **Workflows edit** | Create, edit, and delete workflows | | Workflows | **Workflows view** | View workflows | | Workflows | **Workflow runs view** | View workflow runs | | Workflows | **Workflow runs execute** | Ability to run workflow | | Plugins | **Plugins edit** | Create, edit, and delete plugins | | Plugins | **Plugin proxies edit** | Create, edit, and delete plugin proxies | | Plugins | **Plugin appearance configure** | Manage appearance of plugins | | Tools | **Relationship graph enable** | View and engage with relationship graph | | Tools | **Onboarding management view** | View onboarding management | | Tools | **Onboarding management enable** | Trigger onboarding management notifications | | Tools | **Discovery audit events configure** | Ignore or import entities found in the discovery audit tool | | Tools | **Scaffolder templates configure** | Create, edit, and delete Scaffolder templates | | Tools | **Scaffolder execute** | Run the Scaffolder | | Tools | **Query builder (basic) enable** | Access to query builder tool that allows CQL queries to be created and run adhoc | | Tools | **Query builder (with 3rd party integrations) enable** | Access to query builder tool that allows CQL queries to be created and run adhoc, including queries of 3rd party integration data | | Notifications | **Workspace notification settings configure** | Enable or disable workspace notification settings | | Notifications | **Notification logs view** | View notification logs | | Notifications | **Notification logs execute** | Resend a notification | | Settings | **Settings configure** | Edit workspace settings, identity mappings, and integration configurations | | Settings | **Appearance settings configure** | Edit workspace appearance settings, including logo upload, plugin placement throughout the app, entity overview tabs and navigation order, and catalog sort order | | Settings | **IP allowlist configure** | Configure restriction for Cortex app and public API access to specified IPs | | Settings | **GitOps logs view** | View GitOps logs | | Settings | **OpenID Connector & SCIM configure** | Manage OpenID application details and SCIM for Auth0, Azure, Google, and Okta | | Settings | **Roles view** | View workspace role definitions and user role assignments | | Settings | **Roles configure** | Manage workspace role definitions and user role assignments | | Settings | **Breaking API changes view** | View breaking API changes | | Settings | **Create API keys edit** | Create, edit, and delete Cortex API keys | | Settings | **Identity mappings configure** | Review how team members defined in the team catalog are matched to external accounts (e.g. GitHub, Jira, PagerDuty, ClickUp, or Slack). | | Settings | **Integrations configure** | Install, uninstall, and configure integrations | | Access Management | **Create secrets edit** | Create, edit, and delete secret keys used in plugin proxies, secure access to 3rd party APIs, etc | | Access Management | **Audit logs view** | View audit logs | > [!NOTE] > > Custom roles that could already view Eng Intelligence were given **View Eng Intelligence User Dimensions** automatically, so existing users keep the access they had. To limit a role to team- and entity-level Eng Intelligence data, turn off **View Eng Intelligence User Dimensions** for that role. # Configuring SCIM in Cortex Source: https://docs.cortex.io/configure/settings/managing-users/scim/configuring-scim Before you begin using SCIM to provision users, you must first turn on SCIM in your Cortex workspace. Follow the steps below to turn on SCIM. 1. From the main sidebar, click your avatar in the bottom-left corner. 2. Click **Settings**. 3. From the **Settings** menu, scroll to the **Security and access** section, then select **SCIM**. 4. Toggle on the following settings: * **Enable automatic deprovisioning of users** - Cortex automatically deprovisions any user it detects has been removed from your provider instance. * **Enable automatic provisioning of users** - Cortex automatically provisions any user it detects has been added to your provider instance. > [!NOTE] > > Enabling automatic provisioning of users may impact seat counts. Each toggle controls a distinct set of SCIM operations: * **Enable automatic provisioning of users** gates user creation and reactivation. While it is off, your provider cannot create or reactivate users in Cortex. * **Enable automatic deprovisioning of users** gates user deletion and deactivation. While it is off, your provider cannot delete or deactivate users in Cortex. A user created or reactivated while automatic provisioning is on is always assigned your workspace's default role. For the API responses returned when a required toggle is off, see the [SCIM API reference](/api/rest/scim). > [!NOTE] > > Track provisioned and deprovisioned users in the [Cortex audit logs](/configure/settings/audit-logs). Access the logs from the **Settings** menu. Scroll to the *Logging* section, then select **Audit logs**. For an overview of the complete SCIM provisioning workflow, see [Okta SCIM Configuration](/configure/settings/managing-users/scim/okta-scim) or [Microsoft Entra ID SCIM Configuration](/configure/settings/managing-users/scim/entraid-scim). # Configuring Microsoft Entra ID SCIM for Cortex Source: https://docs.cortex.io/configure/settings/managing-users/scim/entraid-scim This article explains how to configure Microsoft Entra ID SCIM to work with Cortex. If you're looking to turn on SSO in Cortex via Entra ID, refer to [this article](/configure/settings/managing-users/configuring-sso/entraid). When Entra ID SCIM is configured, you can create, import, edit, and deactivate users. > [!NOTE] > > Prior to configuring Entra ID SCIM, you must first turn on SCIM in Cortex. Refer to [Configuring SCIM in Cortex](/configure/settings/managing-users/scim/configuring-scim) for more information. ## Prerequisites Create an API key in Cortex that has the **Admin** role or a custom role that contains the `Configure Open ID Connector & SCIM`, `Edit Roles`, and `Manage Identity Mappings` permissions. See [API Keys, Secrets, and Tokens](/configure/settings/api-keys#create-api-key) for more information. > [!NOTE] > > Be sure to copy the API key and save it for later. Do not skip this step—you can only view the key once! ## Step 1: Adding an Entra ID non-gallery application for SCIM You must be logged in to Entra ID as one of the following roles: Application Administrator, Cloud Application Administrator, or Global Administrator. 1. Log in to the Microsoft Entra Admin Center at [https://entra.microsoft.com](https://entra.microsoft.com). 2. Navigate to **Entra ID > Enterprise apps**. 3. Click **+ New application**. 4. Click **+ Create your own application**. 5. Enter the application name, i.e. `Cortex SCIM`. 6. Select **Integrate any other application you don't find in the gallery (Non-gallery)**. 7. Click **Create**. ## Step 2: Configuring Entra ID automatic provisioning for SCIM You must be logged in to Entra ID as one of the following roles: Application Administrator, Cloud Application Administrator, or Global Administrator. ### Setting up the connection between Cortex and Entra ID 1. Log in to the Microsoft Entra Admin Center at [https://entra.microsoft.com](https://entra.microsoft.com). 2. Navigate to **Entra ID > Enterprise apps**. 3. Open the Cortex SCIM application you created in [Step 1: Adding an Entra ID Non-gallery Application for SCIM](/configure/settings/managing-users/scim/entraid-scim#step-1). 4. From the left menu, select **Provisioning**. 5. Click **Connect your application**. 6. Below **Admin Credentials**, complete the following fields: 1. From the **Select authentication method** drop-down menu, select **Bearer authentication**. 2. In the **Tenant URL** field, enter `https://api.getcortexapp.com/scim/v2`. 3. In the **Secret token** field, enter your Cortex-generated API key. 7. Click **Test Connection**. A **Success** message appears. 8. Click **Create**. ### Configuring scope in Entra ID Follow the steps below to set the user provisioning scope. 1. Log in to the Microsoft Entra Admin Center at [https://entra.microsoft.com](https://entra.microsoft.com). 2. Navigate to **Entra ID > Enterprise apps**. 3. Open the Cortex SCIM application you created in [Step 1: Adding an Entra ID Non-gallery Application for SCIM](/configure/settings/managing-users/scim/entraid-scim#step-1). 4. From the left menu, select **Provisioning**. 5. Select the **Properties** tab. 6. Click the **pencil icon** next to Basics. 7. In the right panel, locate the **Scope** drop-down menu, then choose one of the following options: * **Sync only assigned users and groups** (recommended) - Only users explicitly assigned to the Cortex SCIM app will be provisioned in Cortex. * **Sync all users and groups** - All users in your directory will be provisioned in Cortex. ## Step 3: Enabling and verifying Entra ID SCIM provisioning You must be logged in to Entra ID as one of the following roles: Application Administrator, Cloud Application Administrator, or Global Administrator. When SCIM provisioning is turned on with Entra ID, the following happens: * Entra ID begins the initial synchronization with Cortex. This process may take 15 to 20 minutes. * Entra ID triggers ongoing incremental synchronizations with Cortex every 40 minutes. > [!NOTE] > > You can monitor the synchronization status in Entra ID via the provisioning logs. Users are created in Cortex based on the user assignments configured in Entra ID. ### Turning on provisioning in Entra ID Follow the steps below to enable user provisioning in Entra ID. 1. Log in to the Microsoft Entra Admin Center at [https://entra.microsoft.com](https://entra.microsoft.com). 2. Navigate to **Entra ID > Enterprise apps**. 3. Open the Cortex SCIM application you created in [Step 1: Adding an Entra ID Non-gallery Application for SCIM](/configure/settings/managing-users/scim/entraid-scim#step-1). 4. From the left menu, select **Provisioning**. 5. Click **Start Provisioning**. ### Verifying provisioning in Entra ID Follow the steps below to confirm successful user provisioning in Entra ID. 1. Log in to the Microsoft Entra Admin Center at [https://entra.microsoft.com](https://entra.microsoft.com). 2. Navigate to **Entra ID > Enterprise apps**. 3. Open the Cortex SCIM application you created in [Step 1: Adding an Entra ID Non-gallery Application for SCIM](/configure/settings/managing-users/scim/entraid-scim#step-1). 4. From the left menu, select **Provisioning**. 5. From the left menu, select **Provisioning logs**. 6. Review the logs for any errors. 7. Verify that users display a **Success** status. > [!NOTE] > > Entra ID synchronizes with Cortex every 40 minutes. If you are within the 40-minute window, there may not be any recent information in the logs. ### Verifying provisioning in Cortex Follow the steps below to confirm successful user provisioning in Cortex. 1. Log in to Cortex. 2. From the main sidebar, click your avatar in the bottom-left corner. 3. Click **Settings**. 4. From the **Settings** menu, scroll to the **Security and access** section, then select **Permissions**. 5. Confirm that users are listed in the **Users** tab. > [!NOTE] > > You can change the default role assigned to new users who are provisioned from Entra ID. Select the *Default role* drop-down menu to change the default role. ### Deprovisioning users When a user is [removed or deprovisioned in Entra ID](https://learn.microsoft.com/en-us/entra/identity/app-provisioning/how-provisioning-works#deprovisioning), the following happens in Cortex: * The user's roles are removed * The user's team memberships are removed * The user's personal API keys are deleted * All of the user's active sessions are immediately invalidated > [!NOTE] > > Removing a Cortex seat does not delete the user's git identity mappings. If they're still active in your git provider (e.g. GitHub), their contribution data continues to be attributed correctly in Eng Intelligence. Deprovisioned users can no longer access Cortex, even if they had an active browser session at the time of removal. No additional action is required to enforce access revocation—removal from your identity provider is sufficient. **Verifying a user has been deprovisioned in Cortex**: 1. Log in to Cortex. 2. From the main sidebar, click your avatar in the bottom-left corner. 3. Click **Settings**. 4. From the **Settings** menu, scroll to the **Security and access** section, then select **Permissions**. 5. Select the **Users** tab, then verify that the user has been removed. # Configuring Okta SCIM for Cortex Source: https://docs.cortex.io/configure/settings/managing-users/scim/okta-scim This article explains how to configure Okta SCIM to work with Cortex. If you're looking to turn on SSO in Cortex via Okta, refer to [this article](/configure/settings/managing-users/configuring-sso/okta). When Okta SCIM is configured, you can create, import, edit, and deactivate users. > [!NOTE] > > Prior to configuring Okta SCIM, you must first turn on SCIM in Cortex. Refer to [Configuring SCIM in Cortex](/configure/settings/managing-users/scim/configuring-scim) for more information. ## Limitations Note the following limitations when using Okta SCIM: * A user's email cannot be changed * Only given and family names can be updated * Users can only be reactivated via a `PUT` operation ## Prerequisites 1. Create an API key in Cortex that has the **Admin** role or a custom role that contains the `Configure Open ID Connector & SCIM`, `Edit Roles`, and `Manage Identity Mappings` permissions. See [API Keys, Secrets, and Tokens](/configure/settings/api-keys#create-api-key) for more information. > **Note:** Be sure to copy the API key and save it for later. Do not skip this step—you can only view the key once! 2. In Okta, navigate to **Applications > Sign on > Credential details** and set the **Application username format** to **Email**. SCIM requires this format. 3. If your organization requires you to allowlist domains, ensure that [Okta's IP addresses](https://support.okta.com/help/s/article/list-of-ip-addresses-that-should-be-allowlisted-for-inbound-traffic) can access your Cortex instance: 1. In Cortex, click your avatar in the bottom-left corner, then click **Settings**. 2. From the **Settings** menu, locate the **Security and access** section, then click **IP allowlist**. If there are no IP addresses listed here, access is allowed from any IP address. 3. Click **Add IP addresses** in the upper-right corner. 4. Enter an individual IP address or an IP range in [CIDR notation](https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing), then click **Add addresses**. ## Step 1: Adding the Cortex OIN app Add the Cortex OIN app for Okta from [Okta's Cortex integration docs](https://www.okta.com/integrations/cortex/). This is also available in your Okta instance under **Applications > App integration catalog**. ## Step 2: Configuring the API integration 1. In your Okta admin dashboard, navigate to **Applications** then click the Cortex app. 2. Click the **Provisioning** tab. 3. Under the **Settings** panel, click **Integration**. Do the following: * Select the **Enable API integration** checkbox. * **API token** - Enter your Cortex-generated API key. 4. Click **Test API Credentials** to verify that your configuration works. 5. Click **Save**. ## Step 3: Turning on provisioning in Okta Provisioning settings can be turned on once the integration is configured. 1. Enable the following settings in Okta: * **Create users** - This creates a user in Cortex when the app is assigned to a user in Okta. * The default username used to create accounts is set to the **Okta username**. * **Update user attributes** - This setting allows Okta to update a user's attributes in Cortex when the app is assigned. * Cortex only supports updating the user's name (i.e. birth and family names). * **Deactivate users** - This deactivates or deletes a user's Cortex account when the app is unassigned to that user or when their Okta account is deactivated. * Accounts can be reactivated if the app is reassigned to the user in Okta. * By default, deprovisioned users will not remain visible in team membership. Contact [Cortex Support](mailto:help@cortex.io) to change this behavior. * When a deprovisioned user is reprovisioned and logs back in with the same email, any ownership or team membership that still references their email will continue to be associated with them. 2. Click **Save**. ## Syncing user data between Okta and Cortex Follow the steps below to force a data sync between Okta and Cortex. 1. In your Okta admin dashboard, open the Cortex app then select the **Provisioning** tab. 2. Under the **Settings** panel, click **To App**. 3. Under **Cortex Attribute Mappings**, click **Force sync**. ## Verifying provisioning in Cortex Follow the steps below to confirm successful user provisioning in Cortex. 1. Log in to Cortex. 2. From the main sidebar, click your avatar in the bottom-left corner. 3. Click **Settings**. 4. From the **Settings** menu, scroll to the **Security and access** section, then select **Permissions**. 5. Confirm that users are listed in the **Users** tab. > [!NOTE] > > You can change the default role assigned to new users who are provisioned from Okta. Select the *Default role* drop-down menu to change the default role. ## Deprovisioning users When a user is [removed or deprovisioned in Okta](https://developer.okta.com/docs/concepts/scim/#delete-deprovision), the following happens in Cortex: * The user's roles are removed * The user's team memberships are removed * The user's personal API keys are deleted * All of the user's active sessions are immediately invalidated > [!NOTE] > > Removing a Cortex seat does not delete the user's git identity mappings. If they're still active in your git provider (e.g. GitHub), their contribution data continues to be attributed correctly in Eng Intelligence. Deprovisioned users can no longer access Cortex, even if they had an active browser session at the time of removal. No additional action is required to enforce access revocation—removal from your identity provider is sufficient. **Verifying a user has been deprovisioned in Cortex**: 1. Log in to Cortex. 2. From the main sidebar, click your avatar in the bottom-left corner. 3. Click **Settings**. 4. From the **Settings** menu, scroll to the **Security and access** section, then select **Permissions**. 5. Select the **Users** tab, then verify that the user has been removed. ## Troubleshooting and FAQ See frequently asked questions below. > **Why might I see a 'Forbidden from remote server' error in Okta when testing authentication?** > > This can happen if you did not configure user provisioning in your SCIM settings in Cortex before testing the integration in Okta. Follow the [steps to configure SCIM](/configure/settings/managing-users/scim/configuring-scim), then try again. > **Do I need the Okta integration set up on the Cortex side to use Okta SCIM?** > > You do not need to have the Okta integration configured on the Cortex side. However, you will still need to use the Cortex Okta Integration Network app within Okta using a valid Cortex API key. # Provisioning Cortex users with SCIM Source: https://docs.cortex.io/configure/settings/managing-users/scim/provisioning-users-with-scim System for Cross-domain Identity Management (SCIM) is an open standard protocol that automates the exchange of user identity information between an identity provider (IdP)—such as Microsoft Entra ID or Okta—and a target application like Cortex. It defines a standard schema and REST API for creating, updating, and deprovisioning user accounts, eliminating the need for manual account management. IT administrators and DevOps teams commonly use SCIM to manage user lifecycles at scale across multiple applications from a single source of truth. By automating user provisioning and deprovisioning, SCIM reduces the risk of human error, ensures access is granted and revoked in a timely manner, and frees up administrators from repetitive manual tasks, making it especially valuable in organizations with large or frequently changing user bases. > [!NOTE] > > Cortex supports SCIM provisioning from [Okta](/configure/settings/managing-users/scim/okta-scim) and [Microsoft Entra ID](/configure/settings/managing-users/scim/entraid-scim). # Notifications Source: https://docs.cortex.io/configure/settings/notifications Notifications are built into Cortex to help users stay on top of changes within their environments and the platform. Admins can [configure notifications for the entire workspace](/configure/settings/notifications#setting-notifications-for-the-entire-workspace), while [users can configure their personal notification subscriptions](/configure/settings/notifications#adjusting-your-personal-notification-subscriptions). See the full list of notification options below under [Notification subscription options in Cortex](/configure/settings/notifications#notification-options-in-cortex). ### Notification markdown limitations It is possible to use markdown in some fields in Cortex. Some of these fields, such as the description field for a [data verification policy](/configure/settings/entity-settings/verification), appear in notifications. While Cortex will render markdown as expected in the UI, Slack and email notifications may have issues rendering some markdown. Markdown limitations include, but are not limited to, the following: * The first element in the description cannot start with `#`. * Slack supports basic lists, but nested lists are not supported. * Multi-line code blocks will lose formatting in Slack. * Inline images with standard markdown (`![alt text](./images/url)`) will not be displayed in Slack. * Strike-through syntax does not render in Slack. * Line breaks may not render in Slack. * Hyperlinks may not be clickable in emails. To read about other Slack limitations, please see [Markdown Guide's documentation on using Markdown in Slack](https://www.markdownguide.org/tools/slack/). ## Setting notifications for the entire workspace In the [Notifications settings](https://app.getcortexapp.com/admin/settings/notifications) page in Cortex, you can enable notifications and refine the types of notifications received by users and teams across the workspace. To set notifications for the workspace, you must be an admin or have a role that includes the `Configure Workspace notification settings` permission. ### Configure allowed notification methods You can choose whether to allow notifications via the following methods: * **Email** * Note that if a user does not have a defined email address, they will not receive email notifications. * **Slack** * You must have the [Slack integration](/ingesting-data-into-cortex/integrations/slack) configured in order to send notifications to entity Slack channels. * **Microsoft Teams** * You must have the [Microsoft Teams ](/ingesting-data-into-cortex/integrations/microsoftteams)integration configured in order to send notifications to entity Teams channels. ### Configure what type of user can receive notifications You can enable the following options across the workspace: * **Enable notifications for non-Cortex users**: When you toggle this setting on, it will enable all notifications for people who are not yet Cortex users but are owners of entities in Cortex. * **Enable notifications for external members**: When you toggle this setting on, it will enable notifications for any Cortex users who are members of an externally-sourced team, such as Workday or Okta. * **Limit notifications through CQL**: Any entity that does not match the query will be excluded from all notifications. For entities that match the query, Cortex will continue sending out notifications to their entity owners. * After you enable this setting, a text box appears. Enter your query into the box, then click **Save query**. ![You can configure notification types in the Notification settings page.](https://mintcdn.com/cortex-290c0c42/GdCQ7wvPeVXdjHh5/images/user-type-notifs.jpg?fit=max\&auto=format\&n=GdCQ7wvPeVXdjHh5\&q=85\&s=a59ace5cf9965c1ed81613307e7a4462) ### Enabling notifications for users, teams, and entities You can enable or disable notifications in the Cortex UI or in an [entity descriptor](/ingesting-data-into-cortex/entities-overview/entities#defining-entities-with-yaml). Note that users also have the ability to unsubscribe from a notification in their [personal settings](/configure/settings/notifications#adjusting-your-personal-notification-subscriptions). #### Understanding notification types Before configuring notifications, it's important to understand the distinction between notifications being enabled for individual users, teams, or entities: | Notification type | Sent to (options) | Example use cases | | - | - | - | | **Team based** These are about the entities owned by a team. | • The Slack or MS Teams channel tied to a **team** in Cortex • Email addresses of team members | • You enable the Team-based "On-call changes" notification and [team itself](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/teams) has a Slack channel linked; When on-call changes for an entity, the team members who own the entity receive a notification. | | **Entity based** These are about the entity itself. | • The Slack or MS Teams channel tied to an **entity** in Cortex If the entity's owner and the entity share the same Slack channel, Cortex will only notify the owner; a duplicate notification won't be sent. | • You enable the Entity-based "On-call changes" notification; When on-call changes for an entity, a notification is sent to the Slack or MS Teams channel linked in the [entity's YAML](/ingesting-data-into-cortex/entities-overview/entities/yaml). • You enable the Entity-based "Initiative Creation" notification; When an entity is included in a recently-created Initiative, a notification is sent to the Slack or MS Teams channel linked in the [entity's YAML](/ingesting-data-into-cortex/entities-overview/entities/yaml). Note that the Initiative must be published, not in draft form. | | **User based** These go to individual users. | • Via DM to the user in Slack or MS Teams (DMs are from the Cortex app) • A user's email address | • You enable the User-based "Onboarding tips" notification; When a new user is added to your workspace, they receive onboarding tip notifications • You enable the User-based "On-call changes" notification; When a user's on-call changes, they receive a notification. | > [!NOTE] > > Note that [some notification types cannot be disabled](/configure/settings/notifications#notifications-that-cannot-be-disabled). #### Configure notifications for users, teams, and entities Expand the tabs below to learn how to configure notifications via the Cortex UI and in an entity's YAML. > **Cortex UI** > > **Configure notifications in the UI** > > On the [notification settings page](https://app.getcortexapp.com/admin/settings/notifications), after configuring the [methods](/configure/settings/notifications#configure-allowed-notification-methods) and [which type of users](/configure/settings/notifications#configure-what-type-of-user-can-receive-notifications) can receive notifications, you can enable individual notifications under the tabs for User, Team-based, and Entity-based: > > 1. For each notification type in the list, enable the toggle to turn on notifications. > > * In each row, there are separate toggles for each allowed notification method. > > ![](https://mintcdn.com/cortex-290c0c42/wjT-J8PNs9MwpcFs/images/notifications-ui.jpg?fit=max\&auto=format\&n=wjT-J8PNs9MwpcFs\&q=85\&s=de4cf24aed40cefa861bbddaea6969d6) > > 2. The notification list defaults to user notifications. Click the **Team-based** and **Entity-based** tabs to review and enable additional notifications. > > * Review the [notification types table](/configure/settings/notifications#understanding-notification-types) above to understand where notifications are sent. > > Read more about each type of notification below under [Notification options in Cortex](/configure/settings/notifications#notification-options-in-cortex). > **Cortex YAML** > > **Define notifications for team members in the entity descriptor** > > If you are configuring the members list for a [team entity](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/teams) via an entity descriptor, you can define the `notificationsEnabled` field as `true` or `false`. When `notificationsEnabled=true`, users/teams will receive all enabled [notification types](/configure/settings/notifications#notification-options-in-cortex) that apply to them. > > The example below demonstrates how to configure notifications for team members in the entity descriptor: > > ```yaml theme={null} > openapi: 3.0.1 > info: > title: Eng Team > x-cortex-tag: eng-team > x-cortex-team: > groups: > - name: Engineering > provider: GITLAB > description: Our engineering team > members: > - name: Maya Chen > role: Engineering Manager > email: maya.chen@cortex-labs.com > notificationsEnabled: true > - name: Andy Li > role: Staff Software Engineer > email: andy.li@cortex-labs.com > notificationsEnabled: false > ``` > > You can also enable or disable notifications for a Slack or Microsoft Teams channel associated with an entity, as shown in the examples below. > > In a service entity: > > ```yaml theme={null} > openapi: 3.0.1 > info: > title: Backend App > x-cortex-tag: backend-app > x-cortex-owners: > - type: SLACK > channel: engineering > notificationsEnabled: true > - name: eng-team > type: group > provider: CORTEX > notificationsEnabled: false > ``` > > In a team entity: > > ```yaml theme={null} > ... > x-cortex-slack: > channels: > - name: team-insights > notificationsEnabled: true > - name: escalate-insights > notificationsEnabled: false > ``` ## Adjusting your personal notification subscriptions Notification subscriptions allow users to further refine the notifications they receive. These settings will override workspace notifications, effectively allowing a user to "unsubscribe" from a given notification type. For example, if a workspace admin has enabled **Entity evaluation** in workspace notifications, but a user has disabled **Entity evaluation** in Notification subscriptions, the user will not receive updates when Scorecard scores change for their entities. To adjust which notifications you receive: 1. Navigate to the [My notifications page in Settings](https://app.getcortexapp.com/admin/settings/notification-subscriptions). ![](https://mintcdn.com/cortex-290c0c42/wjT-J8PNs9MwpcFs/images/my-notifications.jpg?fit=max\&auto=format\&n=wjT-J8PNs9MwpcFs\&q=85\&s=35a8c48cc53353044f94721ca33baa77) 2. For each notification option, use the toggle switch to enable or disable notifications. If an admin has disabled a notification type in [workspace notifications](/configure/settings/notifications#setting-notifications-for-the-entire-workspace), users will **not** be able to enable it. Disabled notification subscriptions will be grayed out. If you hover over the toggle switch, you will see a banner stating, "This notification has been disabled by your Admin." If a notification type has been enabled, but the notification method (e.g., Slack, MS Teams, or email) is disabled, the same note will appear under the notification method toggle for each notification type. ## Notification options in Cortex ### Notifications that cannot be disabled The following notification types cannot be disabled via workspace settings or in an individual user's notification settings: * API token expiration * [On-call assistant](/ingesting-data-into-cortex/entities-overview/entities/oncall-assistant) * Broken OpenAPI spec * Cortex contract or trial expiration * This notification goes to users with the `Configure settings` permission. ### Configurable notification options The configurable notification options are listed below. As described earlier on this page, an admin (or a user with the `Configure Workspace notification settings` permission) can choose which of these options are [available across the workspace](/configure/settings/notifications#setting-notifications-for-the-entire-workspace). If an entity channel and owner channel are the same, Cortex will not send duplicate notifications; in this case, Cortex will only send the owner a notification. Note that notifications can be sent to private Slack channels, but the [Cortex Slack Bot](/ingesting-data-into-cortex/integrations/slack/using-the-integration-for-slack-ai-assistant#adding-the-ai-assistant-to-a-slack-channel) must be a member of the channel in order for the notification to be delivered to the channel. > **Entity evaluation (users only)** > > Entity evaluation notifications go out to users when an entity they own is re-evaluated by a Scorecard due to changes in its `cortex.yaml` file. This alert will tell you whether the score for that entity has increased or decreased. > > **You will not receive a notification if the score is unchanged after Cortex processes the changes.** > **Initiative creation (users, teams, and entities)** > > Draft Initiatives only trigger notifications for users with the `Edit Scorecards` permission. Notifications for draft Initiatives will not trigger for team notifications. > > * Initiative creation notifications alert **teams** *when at least one entity they own is included in a recently created Initiative*. These notifications include [action items](/improve/initiatives) associated with entities owned by that team. > * Initiative creation notifications are sent to **users** *when entities they own are included in a recently created Initiative*. Initiative creation notifications will go to users when an entity is not owned by a team, and/or when the **Initiative creation - Teams** notification is disabled. > * Initiative creation notifications are sent to **entity channels** *when the entity is included in a recently created Initiative*. Cortex checks for created Initiatives and sends relevant notifications every 10 minutes. > **Initiative custom scheduled reminders (users and teams)** > > Draft Initiatives only trigger notifications for users with the `Edit Scorecards` permission. Notifications for draft Initiatives will not trigger for team notifications. > > Initiative custom scheduled reminders send progress notifications to users that are part of a given Initiative. The Initiative owner can determine the cadence of these reminders when creating or editing an Initiative. > **Initiative reminders (users and teams)** > > Draft Initiatives only trigger notifications for users with the `Edit Scorecards` permission. Notifications for draft Initiatives will not trigger for team notifications. > > Initiative reminders alert users 7 days and 1 day before an Initiative's target date. The notification will include the amount of time that remains for an Initiative and a given user's uncompleted action items. > **Integration configuration errors (users only)** > > Integration configuration error notifications notify users with `Configure settings` permissions when the configuration for an integration has been changed and is no longer valid. > > Cortex runs a nightly cron job that checks to ensure configurations are valid; when it detects a change that makes the configuration invalid, admins will receive a notification around 2 p.m. UTC alerting them to fix it. > **Onboarding tips (users only)** > > Onboarding tip notifications send out important information about getting started with Cortex. This notification can be enabled or disabled for the workspace and your personal notification settings. > **On-call changes (users, teams, and entities)** > > On-call change notifications are sent to users, teams, and/or entities when the appointed user on call changes. These notifications will go out about 1 hour before an on-call shift. > **On-call reminder (users only)** > > On-call reminder notifications notify the user on call for a given entity 7 days and 1 day before an on-call shift. **Reminder notifications don’t have to go to a designated entity owner.** > **OpEx mentions (users only)** > > OpEx mention notifications go out to users when someone @mentions them in a comment on an [OpEx Review report](/improve/opex-review/using-opex#commenting-on-a-report). > **OpEx thread activity (users only)** > > OpEx thread activity notifications go out to users when someone replies to an OpEx Review comment thread they've commented on, or resolves a thread they started. > **New scheduled rules created (users, teams, and entities)** > > New scheduled rules created notifications go to users, teams, and/or entities when a scheduled rule is added to a Scorecard evaluating an entity they own. > > Notifications for draft Scorecards will only trigger for users that have the `Edit Scorecards` permission. Notifications for draft Scorecards will not trigger for team notifications. > **Rule exemption request (users only)** > > Rule exemption request notifications alert users with `Configure Scorecards` permissions when a rule exemption is requested for a given [Scorecard](/standardize/scorecards). > > Cortex checks for requested rule exemptions and sends relevant notifications every 10 minutes. > **Scheduled rules reminder (users, teams, and entities)** > > Scheduled rules reminders are sent to users, teams, and/or entities 7 days and 1 day before a scheduled Scorecard rule impacting one of their owned entities goes into effect. > > Notifications for draft Scorecards will only trigger for users that have the `Edit Scorecards` permission. Notifications for draft Scorecards will not trigger for team notifications. > **Score drop (teams and entities)** > > Score drop notifications go to teams and entities after an entity is evaluated by a Scorecard, if its score dropped. > **Verification period started (users only)** > > Verification period started notifications go out to users when a verification period begins that impacts one of their entities. > **Verification period reminder (users only)** > > Verification period reminders go out to users on Mondays with information about entities that require verification during ongoing verification periods. > **Weekly report (users, teams, and entities)** > > Weekly report notifications go out to users, teams, and/or entities on Mondays with information about entities associated with that user. These notifications will let users know how their entities are performing against Scorecards and Initiatives. This will include scores that improved or dropped, pull requests that are open and waiting for your review, and Jira tickets assigned to you. > > The team-based weekly report notification also includes information about who is on call for entities owned by that team. > **Workflow status (users only)** > > Workflow status updates go out to users if a workflow fails or if someone runs a workflow that requires approval. ## How notifications are triggered Draft Scorecards and Initiatives only trigger notifications for users with the `Edit Scorecards` permission. | Notification type | Cortex will notify you: | | - | - | | **Entity evaluation** | When Scorecard scores for a given entity are re-evaluated because of changes to that entity's `cortex.yaml` | | **Initiative creation** | With information about recently created Initiatives you are a part of | | **Initiative custom scheduled reminders** | Information about a given Initiative's progress at a cadence defined by the Initiative owner | | **Initiative reminders** | Reminders a few days before a given Initiative expires with the remaining action items | | **Integration configuration errors** | If any of your integration configurations are invalid and need to be updated | | **Onboarding tips** | With a welcome message and important information, including a set of onboarding tips | | **On-call changes** | When on-call changes for an entity you own | | **On-call reminder** | With a reminder a few days before you're on call | | **OpEx mentions** | When someone mentions you in a comment on an OpEx Review report | | **OpEx thread activity** | When someone replies to an OpEx Review thread you've commented on, or resolves a thread you started | | **Rule exemption request** | When a Scorecard rule exemption is requested | | **Weekly report** | Details about how your entities are tracking against Scorecards and Initiatives (sent on Mondays) | | **Workflow status** | When a workflow fails or someone runs a workflow that requires approval | ## Troubleshooting and FAQ #### I didn't receive an expected notification. How can I troubleshoot this? Ensure that the user has an email address defined. Check whether the user has disabled the notification in their [My notification settings](https://app.getcortexapp.com/admin/settings/notification-subscriptions) page. Please also ensure that the user type is allowed to receive notifications, as configured in your workspace [notification settings](/configure/settings/notifications#configure-what-type-of-user-can-receive-notifications). # Notification logs Source: https://docs.cortex.io/configure/settings/notifications/logs Notification logs allow you to understand and monitor what [notifications](/configure/settings/notifications/logs) are being sent for your workspace, who they're sent to, and how users are engaging with them. ![See the notification list on the notification logs page](https://mintcdn.com/cortex-290c0c42/wjT-J8PNs9MwpcFs/images/notification-logs-page.jpg?fit=max\&auto=format\&n=wjT-J8PNs9MwpcFs\&q=85\&s=f08775cde2a9dd7d6265af69593e739c) ### Log retention Notification logs are retained for 30 days, and the contents of the notifications are retained for 14 days. ## Accessing notification logs in Cortex You can view notification logs in the Cortex UI or fetch them through the [Cortex API](/configure/settings/notifications/logs#access-notification-logs-via-api). ### Access notification logs via the Cortex UI Users with the `View notification logs` permission can access notification logs in Cortex under [**Settings > Notification logs**](https://app.getcortexapp.com/admin/settings/notification-logs). **Notification log summary** The summary at the top of this page includes: * A count of how many notifications are enabled * In the upper right corner of the Notification logs page, click **Workspace notifications** to visit the Notifications page where you can review the list of enabled notifications. * The number of notifications delivered in the last 7 days * The number of notifications that failed to deliver in the last 7 days ![The notification log summary is at the top of the page](https://mintcdn.com/cortex-290c0c42/wjT-J8PNs9MwpcFs/images/notification-log-overview.jpg?fit=max\&auto=format\&n=wjT-J8PNs9MwpcFs\&q=85\&s=1876465b9efbe90ac35f823a09137e88) **Notification log list fields** The list of notifications includes: * Timestamp when the notification was sent * The timestamp is based on the client timezone from your browser. Hover over the timestamp to view the timezone being used. * The name of the notification * An icon appears next to the notification name to indicate which medium was used to notify the user. * The status * Statuses include: * `Completed`: The message was delivered successfully. * `Completed with errors`: Some recipients received the notification, but some did not. Click the notification to review details. * `Failed`: Notification failed to be delivered. * `Ignored`: The notification was ignored. This can occur for several reasons, including: * `Disabled workspace`: This status will appear if the notification medium has been disabled for the workspace, but there was an attempt to send a notification via that medium. For example, if an email notification is triggered, but email notifications are disabled for the workspace. * `Scorecard disabled`: Notifications are disabled for a scorecard. * `Created`: The notification has not yet been sent. If this occurs, try [resending the notification](/configure/settings/notifications/logs#resend-a-notification). * How many times it was sent * The object that triggered the notification (e.g., a Scorecard, entity, initiative, etc.) * The ability to resend the notification. ### Filter the notification logs list 1. In the upper right corner of the list, click **Filter**. 2. Select and configure filters for any of the following: * Failed reason * Ignored reason * Notification source * Notification type * Status ![Click the Filter icon then apply filters](https://mintcdn.com/cortex-290c0c42/wjT-J8PNs9MwpcFs/images/notification-log-filter.jpg?fit=max\&auto=format\&n=wjT-J8PNs9MwpcFs\&q=85\&s=72e1b3506a5df6dfee2c78a50da286dc) 3. Click **Apply**. You can also sort by date: 1. Click **Date** in the upper right corner. 2. Choose whether to sort ascending or descending. ### **View more information about a notification** Click into a log to open a side panel showing the date a notification was sent, when it was last resent, who the recipients of the message were, and the contents of the notification: ![A side panel shows more details about the notification](https://mintcdn.com/cortex-290c0c42/wjT-J8PNs9MwpcFs/images/notif-log-example.jpg?fit=max\&auto=format\&n=wjT-J8PNs9MwpcFs\&q=85\&s=dd9b9b1c7fa5f02b39625152a9492503) Notification logs are retained for 30 days, and the contents of the notifications are retained for 14 days. ## **Resend a notification** Users with the `Execute notification logs` permission can resend a notification to all users, or to specific users. To resend a notification: 1. Locate the notification in the list. 2. In the row for the notification, click the **Resend** icon on the right side. ![Click the Resend icon at the end of the row](https://mintcdn.com/cortex-290c0c42/TKBM5XkYAo_gc56V/images/resend-notifications.jpg?fit=max\&auto=format\&n=TKBM5XkYAo_gc56V\&q=85\&s=1542668949386b574caf17732d6cb431) 3. A confirmation modal will appear. 1. If the previous notification did not successfully send to all recipients, you will have the option to only resend to recipients who didn't receive the notification. ![](https://mintcdn.com/cortex-290c0c42/TKBM5XkYAo_gc56V/images/resend-modal.jpg?fit=max\&auto=format\&n=TKBM5XkYAo_gc56V\&q=85\&s=667e7ef6d621c24fe81cd39b9c20ea6b) 4. Click **Resend notification**. ## Access notification logs via API Notification logs can also be accessed through the [public API endpoint](/api/rest/notification-logs). # Scorecard settings Source: https://docs.cortex.io/configure/settings/scorecard In Settings, admins can adjust general settings for Scorecards and view a list of Scorecard rule exemptions. ## **Accessing Scorecard settings** 1. From the main sidebar, click your avatar in the bottom-left corner. 2. Select **Settings**. 3. From the **Settings** menu, locate the **Workspace** section, then expand **Scorecards**. 4. For general preferences, select the **General** tab. To view exemptions, select the **Rule exemptions** tab. ## General tab ![Scorecards Settings](https://mintcdn.com/cortex-290c0c42/NB69iX-cK6Jnsvqi/images/scorecards-settings.png?fit=max\&auto=format\&n=NB69iX-cK6Jnsvqi\&q=85\&s=f595602958667027543390d6c7f2d8b1) From the **General** tab, admins can configure the following preferences. In the **Preferences** section: * **Show absolute scores in Scorecards** - Toggle this setting on to show scores as absolute scores rather than percentages. This toggle affects the setting for all users. * **Aggregate child scores in Team Scorecards by default** - Toggle this setting on to default to showing aggregated child scores on Team Scorecards. * **Aggregate child scores in Domain Scorecards by default** - Toggle this setting on to default to showing aggregated child scores by default on Domain Scorecards. In the **Scorecard evaluation window** section: * **Minimum evaluation window** - Enter the minimum number of hours between Scorecard evaluations. The default is 4 hours, which is also the shortest window you can set. Increase this value to evaluate a Scorecard less often. * **Default evaluation window (in hours)** - By default, Scorecards are evaluated every 4 hours. You can set a longer evaluation window (in hours), but not a shorter one. ## Rule exemptions tab From this tab, admins can view a list of all rule exemptions. They can accept, reject, and revoke exemptions from this page. ![Scorecards Exemptions Settings List](https://mintcdn.com/cortex-290c0c42/NB69iX-cK6Jnsvqi/images/scorecards-exemptions-settings-list.png?fit=max\&auto=format\&n=NB69iX-cK6Jnsvqi\&q=85\&s=fde7db25e8bd92053eaa042eb02c5237) Do any or all of the following: * Click **Filter** to narrow the list by status, entity, group, rule, requester, or approver. * Click **Timestamp (default)** to sort exemptions based on expiration, rule, Scorecard, status, and timestamp (new to old OR old to new). * On an exemption card, click **Details** to see who requested the exemption and when, the reason they gave, who approved it and when, and its expiration date. Learn more about managing exemptions in [Scorecard rule exemptions](/standardize/scorecards/rule-exemptions). # Using search in Cortex Source: https://docs.cortex.io/configure/settings/search Cortex offers two ways to search across your data: * The **catalog search bar** is found in the upper-right corner of a list, e.g. the catalog list. * The **global search** is found at the top of the main sidebar and lets you run a quick search from anywhere in Cortex across names, descriptions, and tags. ## Using the catalog search bar When you need to find a specific entity in Cortex, use the search bar at the top of any catalog. See the [available operators](/configure/settings/search#search-index-and-operators) below. 1. Navigate to a catalog. 2. In the upper-right corner, enter text into the search bar. Note that you can use plain text for a basic search, or use operators to refine your search.\ ![The search bar, located in the upper-right corner of a catalog page.](https://mintlify.s3.us-west-1.amazonaws.com/cortex-290c0c42/images/entity-search-bar%20%281%29.png) ### Search suggestions and recent searches The search bar shows you which fields it can search against, so you don't have to remember the syntax. Click into the search bar to see the available fields: * Title (entity title) * Tag * Group * Owner * Member * Repository Select a field to add it to your query. Cortex keeps the results open while you keep refining. As you type, the search bar shows which field your query is matching on. By default, a query matches on the entity's name. To match on something else, select a field from the search bar or enter its operator directly. For the full list, see [Search index and operators](/configure/settings/search#search-index-and-operators). If you've searched this catalog before, your recent searches appear as a section in the search bar. Select one to run it again. Recent searches drop out of the list as you type, once they no longer match what you've entered. ### **Query syntax** The catalog search bar supports web search–style syntax: | Syntax | Example | Behavior | | - | - | - | | Multiple terms | `payments api` | Implicit AND — returns results matching all terms | | `or` keyword | `payments OR billing` | OR — returns results matching either term | | Quoted phrase | `"payment service"` | Matches the exact phrase | | Negation (`-`) | `payment -legacy` | Excludes results containing the term after `-` | | `field:value` | `owner:maya.chen@acme.com` | Scoped to a specific field (see table below) | You can combine these: `owner:maya.chen@acme.com tag:payments -deprecated` ### Search index and operators Cortex supports field-based specifiers for searching. A `prefix:value` token is treated as a field filter only when the prefix is a recognized search field (such as `owner:`, `tag:`, or `repo:`). Colons and other special characters in unrecognized positions are treated as plain text, so queries like `https://example.com` won't break. To search for a multi-word value, wrap it in double quotes (e.g., `owner:"Maya Chen"`). | Search field | Corresponding YAML field | Explanation | Examples (based on sample YAMLs below) | | - | - | - | - | | `title:` or `name:` | `title` | Searches for the entity's name as defined in the `title` field. | • payments api • payments • title:"payments api" • name:"payments api" | | `tag:` | `x-cortex-tag` | Searches for a Cortex tag as defined in the `x-cortex-tag` field. If a tag has more than one term separated by a hyphen, you can search for the tag using hyphens or spaces. At least one of these (or a wildcard) must be used for results to be generated. | • payments-api • payments • tag:"payments-api" • tag:"payments" | | `group:` | `x-cortex-groups` | Searches for entity group names. | • payments • backend • group:"payments" • group:"backend" | | `owner:` | `x-cortex-owners` | Searches for the owner(s) of an entity. If the owner is a team, Cortex searches team names and team members' names and email addresses. If the owner is an individual, Cortex searches for the user email. | • payments engineering • maya.chen • owner:"payments" • owner:"maya" | | `member:` | `x-cortex-team`, `members` | Searches for the name and email address for a team member. This query only returns Team entities. | • maya chen • maya.chen • member:"maya" • member:"chen" | | `repo:` or `repository:` | `x-cortex-git`, `repository` | Searches for a Git repository name. | • acme/payments-api • payments-api • repo:"payments-api" • repo:"acme/payments-api" | | `cid:` | (depends on integration) | Searches for an ID associated with an entity. This usually comes from a third-party integration. | • P1AB2CD • cid:"P1AB2CD" | | `description:` | `description` | Searches for the supplied term(s) in an entity's description. | • payment processing • transaction management • description:"payment" - description:"transaction" | | `slack:` | `x-cortex-slack` | Searches for a Slack channel name defined in the `x-cortex-slack` field. | • payments-alerts • payments-eng • slack:"payments-alerts" • slack:"payments" | | `microsoft-team:` | `x-cortex-microsoft-teams` | Searches for a Microsoft Teams channel name defined in the `x-cortex-microsoft-teams` field. | • payments-alerts • Payments Engineering • microsoft-team:"payments-alerts" • microsoft-team:"payments" | | `repo-basepath:` or `repository-basepath:` | `x-cortex-git`, `basepath` | Searches for a Git repo basepath name. | • services/payments • repo-basepath:"services/payments" | | `link:` | `x-cortex-link` | Searches for link based on `name` and `URL` defined under `x-cortex-link`. | • runbooks.acme.com • payments api runbook • link:"runbook" • link:"runbooks.acme" | | Custom data (`key`:`value`) | `x-cortex-custom-metadata` | Searches for custom data imported from APIs, third-party integrations, and/or defined in the `x-cortex-metadata` block. The key is case-sensitive. | • tier:1 • region:us-east-1 | | `aws-account-id:` | Defined in AWS, not in an entity's YAML | Searches for the AWS account ID of an entity. | • aws-account-id:"012345678901" | | `aws-account-name:` | Defined in AWS, not in an entity's YAML | Searches for entities with an AWS account name. | • aws-account-name:"example-aws-account" | | `aws-region:` | Defined in AWS, not in an entity's YAML | Searches for entities in an AWS region. | • aws-region:"us-west-1" | | `aws-type:` | Defined in AWS, not in an entity's YAML | Searches for entities of a given AWS entity type. | • aws-type:"lambda" | | `aws-name:` | Defined in AWS, not in an entity's YAML | Searches for an AWS entity name. | • aws-name:"abc-lambda" | | `aws-identifier:` | Defined in AWS, not in an entity's YAML | Searches for an AWS primary identifier. | • aws-identifier:"value" | | `aws-secondary-identifier:` | Defined in AWS, not in an entity's YAML | Searches for an AWS secondary identifier. | • aws-secondary-identifier:"value" | | `aws-arn:` | Defined in AWS, not in an entity's YAML | Searches for an Amazon Resource Name (ARN). This is not supported for Cloud Control types. | • aws-arn:"arn:aws:iam::123456789012:user/johndoe" | #### Example YAML files The YAML files below show what an entity might look like based on the examples in the table above: **'Payments API' entity YAML** ```yaml theme={null} info: title: Payments API description: Core service handling payment processing and transaction management. x-cortex-tag: payments-api x-cortex-type: service x-cortex-groups: - payments - backend x-cortex-git: github: repository: acme/payments-api basepath: services/payments x-cortex-link: - url: https://runbooks.acme.com/payments-api name: Payments API runbook type: RUNBOOK x-cortex-owners: - name: payments-engineering type: group provider: CORTEX - type: email email: maya.chen@acme.com x-cortex-oncall: pagerduty: id: P1AB2CD type: SERVICE x-cortex-slack: channels: - name: payments-alerts notificationsEnabled: true - name: payments-eng notificationsEnabled: true x-cortex-microsoft-teams: channels: - name: payments-alerts teamName: Payments Engineering description: Alerting channel for the Payments Engineering team. notificationsEnabled: true x-cortex-metadata: tier: "1" region: us-east-1 ``` **'Payments engineering' team YAML** ```yaml theme={null} info: title: Payments Engineering description: Team responsible for payment processing services and infrastructure. x-cortex-type: team x-cortex-tag: payments-engineering x-cortex-team: groups: - name: acme/payments-engineering provider: GITHUB members: - name: Maya Chen email: maya.chen@acme.com notificationsEnabled: true ``` ### When a search returns no results When a search returns nothing, Cortex explains why instead of showing an empty list. The empty state tells you what the query matched on and suggests other searches to try, along with the number of results each suggestion would return. Select a suggestion to run it. A few other things to check when a search comes up empty: * The term you're looking for might live in a field other than the name, such as the owner or the repository. Try one of the suggested searches, or enter the operator yourself, for example `owner:"Maya Chen"` or `repo:"payments-api"`. * Multiple terms are combined with an implicit AND, so `payments api` only returns entities matching both. Use `OR` to broaden the search, as in `payments OR billing`. * Check for a stray `-` in your query. Anything after a hyphen is excluded from the results. * The entity might be archived. Click **Display**, then turn on the option to show archived entities. * You might be on the **Mine** tab, which only covers entities you own or are a member of. Select the **All** tab to search across every entity. ## Using global search You can search the Cortex platform from any page using the global search function. Global search pulls from names, descriptions, and tags. > [!NOTE] > > In-app quick search (Cmd+K) includes entity type filter chips, letting you narrow results by type—service, domain, resource, and more—without leaving the keyboard-driven flow. 1. From the main sidebar, click **Search**. The **Search** window opens.\ ![The global search option, located in the main sidebar.](https://mintcdn.com/cortex-290c0c42/kB9I5hpwwMkz0yx1/images/global-search.png?fit=max\&auto=format\&n=kB9I5hpwwMkz0yx1\&q=85\&s=cb81db584ff0a04127830ba015cc67ca) 2. Enter text into the search bar. Cortex global search covers all items by default, with tabs available to filter results by entities, Initiatives, catalogs, plugins, Scorecards, Workflows, or CQL reports. Clicking any result navigates directly to that item. The first 10 results are displayed in the modal. Click **See all** to view additional results. ![The highlighted 'See all' link, used to view all search results.](https://mintcdn.com/cortex-290c0c42/HbTtnyKVq-sSUnnp/images/in-app-search.png?fit=max\&auto=format\&n=HbTtnyKVq-sSUnnp\&q=85\&s=be5fa89553f40cbf511d34b4b67c82ff) Optionally, in the bottom-right corner of the **Search** window, toggle on **Show archived** to include archived items in the search results. Cortex saves your selection and restores it the next time you open this window. ![The highlighted 'Show archived' toggle in the bottom-right corner of the Search window.](https://mintcdn.com/cortex-290c0c42/HbTtnyKVq-sSUnnp/images/in-app-search2.png?fit=max\&auto=format\&n=HbTtnyKVq-sSUnnp\&q=85\&s=4529f05e4764b6e3a68efa05ba402e82) ## Search AWS details Additional keys are available for searching AWS details in Cortex. See [Searching AWS entities in Cortex](/ingesting-data-into-cortex/integrations/aws/using-the-integration-for-aws#searching-aws-entities-in-cortex) for more information. # Customizing your workspace Source: https://docs.cortex.io/configure/settings/workspace-customization Cortex is built around customization, and the plugin framework extends this to the appearance of your workspace. ## Customizing the look of Cortex Users with the `Configure Appearance Settings` permission can adjust workspace appearance settings. 1. From the main sidebar, click your avatar in the bottom-left corner. ![The circle icon with your initials in the bottom-left corner.](https://mintcdn.com/cortex-290c0c42/WsEW6MxYeKygvxWi/images/avatar.png?fit=max\&auto=format\&n=WsEW6MxYeKygvxWi\&q=85\&s=698acd8b31d3c09550401b8a05e474d4) 2. Click **Settings**. The *General* settings page is displayed. 3. Do any or all of the following: 1. View your organization's billing information, including user login information. 2. Upload your organization's logo. The recommended minimum file size to display the logo in the expanded navigation is `200px x 80px`, and `80px x 80px` for collapsed navigation. 3. Edit your organization's workspace name. 4. Edit your organization's workspace brand colors. Note that this be a hex code, e.g. #800080. 4. Click **Save changes**. ## Customizing the main sidebar * Users with the `Configure Appearance Settings` permission can adjust workspace appearance settings. * Users with the `Configure Plugin Appearance` permission can configure where plugins appear. Follow the steps below to reorder the main sidebar, controlling which catalogs and plugins appear and in what order. 1. From the main sidebar, click your avatar in the bottom-left corner. ![The circle icon with your initials in the bottom-left corner.](https://mintcdn.com/cortex-290c0c42/WsEW6MxYeKygvxWi/images/avatar.png?fit=max\&auto=format\&n=WsEW6MxYeKygvxWi\&q=85\&s=698acd8b31d3c09550401b8a05e474d4) 2. Click **Settings**. 3. Select the **Main sidebar** tab. 4. From the **Catalogs** tab, do the following: 1. Locate the catalog you want to reorder. 2. Hover over the **grip icon** and drag it to the desired position. 5. From the **Plugins** tab, do the following: 1. Locate the plugin you want to reorder. 2. Hover over the **grip icon** and drag it to the desired position. 3. To remove a plugin from the main sidebar, click the **trash icon** next to it. 4. To add a plugin to the main sidebar, click the *Select plugins* drop-down menu and select the plugin you want to add. A maximum of 5 plugins can be displayed in the main sidebar. If 3 or more are selected, they are nested under **Plugins**. Note that only plugins with a global context appear in the main sidebar. 6. Click **Save changes**. > [!NOTE] > > For more information on customizing where plugins appear in Cortex, see [Viewing plugins](/streamline/plugins#viewing-plugins). # Cortex AI chat Source: https://docs.cortex.io/cortex-ai-chat Ask Cortex AI questions about your engineering data from anywhere in Cortex RESEARCH PREVIEW Cortex AI is Cortex's AI-powered chat assistant. It answers questions about your engineering data in plain language, using the same data that powers your Scorecards, dashboards, and reports. Questions that would otherwise become a research task, like who owns this service, which teams are behind on a Scorecard, or how deployments are trending over the last quarter, get answered where you are, without assembling the data yourself. Every answer is grounded in your real Cortex data. > [!WARNING] > > **Cortex AI is not limited to the entities you can see** > > * Anyone with the Enable AI Chat permission can ask about any metric or Scorecard score for any entity in your workspace, including ones hidden from them elsewhere in Cortex. > * Your own conversations stay private. > > ​Treat the `Enable AI Chat` permission as access to your organization's engineering data as a whole, and grant it accordingly. > [!NOTE] > > **Cortex AI chat is in Research Preview** > > * Responses can be slow, especially for questions spanning many teams or entities. > * Not all Cortex data is reachable from chat yet, so it can't answer every question about your organization. > * It can't take action on your behalf. It won't create or edit Scorecards, Initiatives, Dashboards, or Workflows, and it won't change the report's content or filters. > > ​We're actively working on improvements. Share feedback with your account team or through the in-product feedback controls. # Accessing Cortex AI ​`Admins` and users with the `Enable AI Chat` permission can use Cortex AI. The same permission covers chat inside OpEx Review. It does not cover the [Slack AI assistant](/ingesting-data-into-cortex/integrations/slack/using-the-integration-for-slack-ai-assistant#using-the-ai-assistant) or the [Cortex MCP](/get-started/cortex-ai-assistant/mcp), which have their own access. ​There are two ways to access Cortex AI chat, and they share the same conversations: ## ​Ask Cortex AI ​**Ask Cortex AI** sits at the bottom of the main sidebar and opens chat in a panel beside whatever you're looking at, so you can ask a question without losing your place. 1. ​Click **Ask Cortex AI** in the main sidebar, or press **⌘J** (**Ctrl+J** on Windows and Linux). !['Ask Cortex AI', highlighted at the bottom of the main sidebar.](https://mintcdn.com/cortex-290c0c42/z5k1sDZlDmCOZ-iP/images/cortex-ai-sidebar.png?fit=max\&auto=format\&n=z5k1sDZlDmCOZ-iP\&q=85\&s=1f2f479a987c78a313a42e8a3a28f6be) 2. Enter your question, then press **Enter**. ​The side panel follows you as you navigate. On an entity or Scorecard page, Cortex AI grounds your next question in what you're looking at. This means you can ask "who owns this?" or "why is this failing?" without naming the thing. Move to a different page and the line updates, so you always know what your next question will be about. ​Press the shortcut again to close the panel. The conversation stays as you move around Cortex, so closing and reopening the panel picks up where you left off. ## Cortex AI **Cortex AI** in the main sidebar opens a dedicated page built for longer sessions, with your conversation history beside the chat. ## What you can ask Cortex AI is built for the questions that come up while you're working, rather than for a fixed set of reports. For example: * ***Who owns payments-service, and when was it last deployed?*** * ***Which services are failing our production readiness Scorecard, and what's the most common failing rule?*** * ***How has deployment frequency changed for my teams over the last quarter?*** * ***Which Workflows have been failing this week?*** * ***What's the status of our Go 1.22 migration Initiative?*** * ***How do I set up a custom Scorecard rule?*** Cortex AI can reach: * **Your catalog** - Entities, ownership, teams, and entity details * **Scorecards** - Definitions, scores, and how entities are performing against them * **Initiatives** - What's in flight and how it's progressing * **Workflows** - Recent runs and which ones are failing * **Eng Intelligence metrics** - Deployment frequency, cycle time, incident metrics, and custom metrics, broken down by team, entity, or time period * **Cortex documentation** - How a Cortex feature works, answered from the public docs To compare what Cortex AI can reach with the Slack AI assistant and the Cortex MCP, see [Data available in each channel](/get-started/cortex-ai-assistant#data-available-in-each-channel). See the [Cortex AI prompt library](/get-started/cortex-ai-assistant/library) for a full list of prompt patterns organized by use case and role. ### Managing your conversations On the Cortex AI page, your past conversations are listed beside the chat. ![The Cortex AI page with past chats highlighted.](https://mintcdn.com/cortex-290c0c42/z5k1sDZlDmCOZ-iP/images/cortex-ai-past-convos.png?fit=max\&auto=format\&n=z5k1sDZlDmCOZ-iP\&q=85\&s=7621c008160d42a3ae5882535aa18714) To access the Cortex AI page, select **Cortex AI** from the main sidebar. From this page you can: * Select a chat to pick it back up. * While in a chat, click the **overflow menu icon** in the upper-right corner to rename or delete it. * Click **New chat** to start a fresh conversation. A conversation you started from an OpEx Review report includes a link back to the report it originated from. ### Who can see your chats Your conversations are private to you. Nobody else in your organization can see them, including admins, and they aren't visible to anyone you send the URL to; a conversation link only opens for the person who created it. # AI in Cortex Source: https://docs.cortex.io/get-started/cortex-ai-assistant All of the ways you can interact with Cortex Cortex answers natural-language questions about your engineering data—services, ownership, Scorecards, Initiatives, incidents, deployments, and more—so you can get answers without digging through the UI yourself. However you ask, answers are grounded in your real Cortex data and respect each individual's permissions. * **In Slack via the AI assistant** - Mention `@Cortex` in a channel or DM to ask questions in plain language. See [Using the AI Assistant](/ingesting-data-into-cortex/integrations/slack/using-the-integration-for-slack-ai-assistant#using-the-ai-assistant) for more information. * **In your AI tools via MCP** - Connect the [Cortex MCP](/get-started/cortex-ai-assistant/mcp) to ask questions from the tools your team already uses. * **In Cortex via Cortex AI** - [Cortex AI](/cortex-ai-chat) is Cortex's AI-powered chat assistant. It answers questions about your engineering data in plain language, using the same data that powers your Scorecards, dashboards, and reports. > [!NOTE] > > Cortex AI is in Research Preview and available to a limited group of customers. To request access, reach out to your Customer Success Manager. Here are a few prompt examples for you to get started with: * ***What are the patterns of incidents on my team over the last 2 quarters? What areas do you recommend we invest in to improve the reliability of our services?*** * ***Give me a summary of everything I worked on and my key accomplishments over the last quarter.*** * ***Has there been an increase in PR sizes recently? Does that correlate with longer review times?*** * ***What is our deployment frequency for the last 30 days across the services I own? Are there any patterns that may be causing that to change compared to the last quarter?*** See the [Cortex AI prompt library](/get-started/cortex-ai-assistant/library) for a full list of prompt patterns organized by use case and role. ## Data available in each channel Cortex AI chat, the Slack AI assistant, and the Cortex MCP don't all reach the same Cortex data yet. Use the table below to choose the right channel for your question. Each channel respects your permissions in Cortex. | Data | Cortex AI chat | Slack AI assistant | Cortex MCP | | - | - | - | - | | Entities and ownership | Yes | Yes | Yes | | Teams | Yes | Yes | Yes | | Scorecards and scores | Yes | Yes | Yes | | Initiatives | Yes | Yes | Yes | | Workflows | Yes | Partial (status alerts) | Yes | | Eng Intelligence metrics (DORA and custom metrics) | Yes | Yes | Yes | | Pull requests, deployments, and CI | Yes | Partial | Yes | | OpEx Review report content | Yes | No | No | | Entity relationships | Partial | Yes | Yes | | Dependencies | No | Yes | Yes | | On-call | No | Yes | Yes | | Custom data | No | Yes | Yes | | Custom events | No | Yes | Yes | | Documentation, log, and runbook links | No | Yes | Partial | | Your entities ("Mine") | Partial | Yes | Yes | | Cortex documentation | Yes | Yes | Yes | For the full list of what each channel can query, see [What you can ask](/cortex-ai-chat#what-you-can-ask) for Cortex AI chat, [Available capabilities](/ingesting-data-into-cortex/integrations/slack/using-the-integration-for-slack-ai-assistant#available-capabilities) for the Slack AI assistant, and [Available MCP tools](/get-started/cortex-ai-assistant/mcp/using-cortex-mcp#available-mcp-tools) for the Cortex MCP. # Cortex AI prompt library Source: https://docs.cortex.io/get-started/cortex-ai-assistant/library Prompts for the AI Assistant and MCP This article contains prompts for interacting with Cortex, inspired by how high-performing engineering teams use Cortex every day. The prompt examples in this article represent effective patterns across different roles and workflows. Use them as a starting point for building your own prompt library tailored to your team and organization. Remember: * **Be specific** - Instead of ***Tell me about services.***, you could say, ***Show me all critical services failing the Production Readiness Scorecard***. This provides you with more actionable information. * **Combine multiple questions when context helps** - Cortex handles complex prompts like ***Who owns orders-api, when was it last deployed, and are there any open incidents?*** You receive richer context in response to one question instead of piecing together three separate queries. * **Reference your organization's specific constructs** - If you've defined custom Scorecards or Initiatives in Cortex, reference them by name. Cortex understands your organization's specific standards and can query against them directly. * **Use follow-up questions to drill down** - Start broad, then go narrow. ***Show me services with failing Scorecards***, followed by ***What specific checks is checkout-service failing?*** moves you from landscape view to action items. * **Build a library of your most-used prompts** - If you ask the same question every Monday morning, save it. Some teams maintain shared prompt libraries so everyone can benefit from patterns that work. ## Use-case based prompts ### Incident response | Prompt | What it does | | - | - | | ***Who owns payments-api and who's currently on-call?*** | Gets you the right contact immediately so you can escalate or start investigating. | | ***What changed in checkout-service in the last 24 hours?*** | Most incidents trace back to a recent change, so this is usually the fastest path to identifying the root cause. | | ***Which services depend on user-auth? Who do I need to loop in?*** | Understanding the blast radius of an incident helps you get the right teams involved before downstream impact compounds. | | ***What are the top P1 incident drivers on my team this quarter?*** | Surfaces patterns across incidents so you can address systemic causes rather than treating each one as isolated. | | ***How is our mean time to resolution trending compared to last quarter?*** | Gives you a clear signal on whether your reliability investments are actually improving response time. | ### Service ownership | Prompt | What it does | | - | - | | ***Which services have no defined owner?*** | Unowned services are the ones most likely to fall through the cracks during an incident, audit, or migration. | | ***Show me all Tier 1 services with no team assigned.*** | Tier 1 services without ownership represent your highest-risk gap. | | ***Which of our upstream dependencies have no on-call rotation configured?*** | A dependency without on-call coverage means there's no clear path to resolution if it goes down after working hours. | | ***If the data-platform team goes on a code freeze, which of our services are affected?*** | Helps you proactively identify risk and communicate impact before a freeze causes surprises. | ### Production readiness | Prompt | What it does | | - | - | | ***Which of my team's services are failing the Production Readiness scorecard?*** | Gives you a prioritized view of which services need attention before gaps become incidents. | | ***Which services are Tier 1 but haven't passed Production Readiness?*** | Your most critical services should meet the highest bar; this tells you exactly where that's not the case. | | ***What are the most common gaps across my team's services?*** | Identifying patterns in failures helps you address systemic issues rather than fixing services one by one. | | ***Which services have no runbook, no on-call rotation, or no defined owner?*** | These three gaps together represent a service that no one can reliably respond to when something goes wrong. | ### Engineering health and trends | Prompt | What it does | | - | - | | ***What are the incident patterns on my team over the last two quarters?*** | Reveals whether your reliability posture is improving over time or if the same failure modes keep recurring. | | ***Has PR size increased recently? Does that correlate with longer review times?*** | Large PRs slow down review cycles and introduce more risk. This tells you whether the two are connected on your team. | | ***Which teams have improved their deploy frequency the most this quarter?*** | Deployment frequency is a leading indicator of team velocity and confidence, so knowing who's improving helps you identify what's working. | | ***What's the overall operational maturity trend for my org over the last 6 months?*** | A high-level view of whether your implementation investments are moving the needle across the organization. | | ***Summarize the key engineering health metrics for my org — I need this for a leadership review.*** | Pulls together the data you'd otherwise spend hours assembling from dashboards, spreadsheets, and status updates. | ### New hire onboarding | Prompt | What it does | | - | - | | ***What dependencies does my team's services have and who owns them?*** | The fastest way to understand your team's scope of responsibility without waiting for someone to walk you through it. | | ***Which of our services have open action items or are failing their Scorecard?*** | Surfaces the most pressing work on your team so you can start contributing without needing a full handoff. | | ***Give me a summary of what my team has shipped in the last 90 days.*** | Gets you up to speed on recent deployments so you can have informed conversations with your team from day one. | ### Migration tracking | Prompt | What it does | | - | - | | ***Which services have been migrated to \[NEW PLATFORM] and which are still pending?*** | Gives you a real-time view of migration progress without chasing teams for status updates. | | ***Which teams haven't completed the migration yet and what's blocking them?*** | Surfaces where the migration is stalling so you can direct support to the right places before deadlines slip. | | ***Which migrated services are failing their scorecard since the cutover?*** | Catches regressions introduced by the migration before they turn into incidents or compliance gaps. | | ***What's the migration completion rate across the org this quarter?*** | Tracks overall migration progress across the org so you know whether you're on pace to hit your target or need to intervene. | ## Role-based prompts ### Prompts for engineers The best prompts for engineers eliminate context switching at the moments when focus matters most. #### Understanding unfamiliar services | Prompt | What it does | | - | - | | ***Tell me about the \[SERVICE NAME] service, including who owns it, what it does, and where the documentation lives.*** | Pulls everything from your Cortex catalog at once. You get ownership, a description of what the service does, links to documentation, and the team's communication channels. Instead of hunting across wikis, Slack, and GitHub, you have the context you need to start working. | | ***Show me the dependencies for \[SERVICE NAME]. Which services does it depend on, and which services depend on it?*** | Understanding the dependency graph is critical when planning changes with potential downstream impact. This prompt reveals what might break and which teams need to be in the conversation before you make a move. | | ***Which Scorecard is \[SERVICE NAME] failing, and what do I need to fix?*** | Transforms maintenance from reactive to proactive. Instead of waiting for your platform team to flag issues or discovering gaps during an incident, you see exactly which Scorecards are failing and what specific checks need attention. You can address production readiness, security, or documentation gaps on your own schedule, before they become blockers. | #### During code review | Prompt | What it does | | - | - | | ***Check the Scorecards for \[SERVICE NAME]. Does this service meet our production readiness standards?*** | Starting here when you're unfamiliar with a service changes the conversation. If the service is already failing key Scorecards, you'll know which questions to ask and where the risks actually are. | | ***Show me recent incidents for \[SERVICE NAME].*** | Past incidents tell you where a service has been fragile. When you see that history before approving changes, you can evaluate whether the PR addresses root causes or introduces new failure modes. | #### Tracking work | Prompt | What it does | | - | - | | ***What Initiatives are assigned to the Engineering team, and what's the status of each?*** | Condenses your weekly status check into a single query. Run it at the start of your week or during standup and you get a complete picture of your Initiative commitments and their current state. Instead of navigating to the Cortex web UI or mentally tracking what you're responsible for, you see everything assigned to you without leaving your IDE or chat interface. | | ***Show me the details for \[INITIATIVE NAME]. What still needs to be done?*** | When you're ready to make progress on a specific Initiative, this surfaces the remaining tasks and their current state. You know exactly what's left and where to focus. | ### Prompts for engineering leaders The best prompts for engineering leaders are about trends, patterns, and the health of systems; these prompts surface the signals that inform strategic decisions. #### Understanding team health | Prompt | What it does | | - | - | | ***Show me MTTR trends over the last quarter. How has it changed?*** | Incident response either gets faster or it doesn't. If MTTR is climbing, something in your system has degraded. This prompt gives you the trend line and a clear signal to investigate process or tooling gaps. | | ***Which teams have the most failing Scorecards right now?*** | Surfaces which teams are struggling with compliance or buried in technical debt. The answer reveals where support and resources should flow. Instead of waiting for teams to escalate problems or discovering issues through incident patterns, you have a clear view of which teams need help right now. That visibility lets you have proactive conversations about priorities, staffing, or process changes before compliance gaps become production incidents. | | ***How has deployment frequency changed over the last six months for the Platform team?*** | Deployment frequency serves as a proxy for both velocity and confidence. When you track this metric over time, you get clear evidence of whether your investments in tooling and process improvements are actually working.If deployment frequency is climbing, teams are shipping faster and feel confident doing it. If it's flat or declining despite investments, you need to investigate whether new tools are adding friction, whether processes are getting in the way, or whether something else is slowing teams down. The trend line tells you whether to double down on your current approach or change course. | #### Tracking AI adoption impact | Prompt | What it does | | - | - | | ***How has AI adoption impacted MTTR and deployment frequency over the last quarter?*** | Connects AI spending directly to concrete business outcomes. When you run this query, you're comparing metrics before and after AI tool adoption. If MTTR dropped and deployment frequency increased after rolling out Copilot or similar tools, you have hard data to justify continued investment and potentially expand the rollout.If the metrics haven't moved despite adoption, you need to ask different questions: Are teams actually using the tools? Do they need more training? Are the tools solving the wrong problems? The comparison gives you evidence to either double down on your AI strategy or course-correct before spending more. | | ***Which teams have adopted AI tools, and how does their velocity compare to teams that haven't?*** | Reveals whether AI adoption is actually delivering the productivity gains you expected. The comparison between adopters and non-adopters gives you a clear control group to measure impact. If teams using AI tools show meaningfully higher velocity, you have validation to expand the rollout and invest more.If there's no significant difference, or if adopters are actually slower, you need to understand why. Maybe teams need better training on how to use the tools effectively. Maybe the tools work better for certain types of work than others. Maybe adoption is superficial and teams aren't integrating the tools into their actual workflows. The data points you toward the right interventions. | #### Spotting bottlenecks | Prompt | What it does | | - | - | | ***Where are the biggest bottlenecks slowing down the Checkout team?*** | When a team's velocity drops unexpectedly, this surfaces the patterns that sprint metrics miss: services with high incident rates, missing documentation, or blocked Initiatives. You get data, not speculation. | | ***Show me services with the highest incident rates in the last month.*** | High incident rates point to deeper reliability issues. This tells you where to invest in stability before those services become everyone's problem. | ### Prompts for platform teams The best prompts for platform teams show you where adoption is working, where it's stalled, and which teams need support. #### Tracking standards adoption | Prompt | What it does | | - | - | | ***Show me how teams are performing on the Production Readiness Scorecard. Which services are failing?*** | Gives you a complete view of compliance across the organization without manually checking each team's services. You see which teams are struggling to meet standards and which services create the most risk. The answer tells you where to focus your enablement efforts and which conversations to prioritize. Instead of discovering compliance gaps reactively during incidents or audits, you have a real-time picture of organizational health. | | ***Which services don't have runbooks, and who owns them?*** | Missing runbooks are incidents waiting to happen. When something breaks at 3 AM, responders need clear guidance to restore service quickly. This prompt shows you exactly which services lack that critical documentation and who's responsible for creating it.With this information, you can prioritize outreach based on service criticality. A critical payment service without a runbook demands immediate attention, while a lower-tier internal tool might wait. Instead of discovering documentation gaps during an active incident when every minute counts, you can systematically close them before they cost you hours of downtime. | | ***Show me AI maturity Scorecard results across all teams. Where are the biggest gaps?*** | If you're driving AI adoption, this reveals which aspects of maturity need attention. The gaps tell you whether teams need training, tooling, process changes, or something else entirely. | #### Managing Initiatives | Prompt | What it does | | - | - | | ***Which services are blocking completion of the \[INITIATIVE NAME]?*** | When an initiative stalls, this identifies exactly which services or teams are holding things up. Now you know where to focus your attention and who needs support. | | ***Show me progress on the Kubernetes Migration Initiative. Which teams are on track, and which are falling behind?*** | Surfaces real-time status across every team involved in the initiative without sending Slack messages or requesting manual updates. You get an immediate picture of which teams are making progress, which are stuck, and which haven't started. That visibility lets you direct support and resources to the teams that need it most, rather than treating every team the same or discovering delays only when deadlines slip. | | ***Give me a plan to get the Checkout team back on track with production readiness.*** | Once you've identified a team falling behind, this generates a concrete action plan based on the specific gaps in their Scorecards and service metadata. You move straight to solutions. | #### Gap analysis | Prompt | What it does | | - | - | | ***Which critical services are missing SLOs?*** | SLOs are foundational to reliability. This scopes the gap and identifies which services should be prioritized based on business impact before an incident forces the conversation. | | ***Show me services without proper monitoring. What's missing?*** | Monitoring gaps are blind spots waiting to bite you during incidents. This surfaces which services need instrumentation and what specific monitoring is absent, so you can build a targeted remediation plan. | ### Prompts for SREs The best prompts for SRE teams focus on proactive incident prevention or responding quickly to a incident in progress. #### During incidents | Prompt | What it does | | - | - | | ***Who's on call for \[SERVICE NAME] right now, and when was it last deployed?*** | The first question in almost every incident. One prompt gets you the owner, the on-call contact, and recent deployment history. You can escalate or start investigating without hunting through five different systems. | | ***Show me recent deploys and changes for \[SERVICE NAME].*** | Most incidents trace back to recent changes. This gives you a timeline pointing to likely culprits so you can focus your investigation on what actually changed. | | ***Show me the incident readiness Scorecard for \[SERVICE NAME]. Are we prepared to respond?*** | Not all services are equally ready for incidents. This tells you whether runbooks exist, whether monitoring is in place, and whether escalation paths are documented. You know what tools you have before you need them. | #### Proactive reliability work | Prompt | What it does | | - | - | | ***Show me services with the highest MTTR in the last month.*** | High MTTR means certain services are consistently difficult to debug or restore. This tells you where reliability improvements will have the biggest impact on your time and your team's sanity. | | ***Which critical services have had the most incidents recently?*** | Frequent incidents signal deeper problems that incident response won't fix. This helps you spot patterns and prioritize services that need architectural investigation, not just patches. | | ***Show me services that are missing runbooks or escalation procedures.*** | When incidents happen, responders need clear guidance. This identifies documentation gaps that will slow response time before they cost you hours during an outage. | ### Prompts for security engineering teams The best prompts for security engineers help them monitor, audit, and enforce security posture across services. #### Compliance monitoring | Prompt | What it does | | - | - | | ***Which services are failing our SOC-2 Scorecard?*** | Gives you a view of SOC-2 compliance across the organization without manually checking each team's services. The answer tells you where to focus your efforts and which conversations to prioritize. Instead of discovering compliance gaps reactively during incidents or audits, you have a real-time picture of organizational health. | #### Proactive security health | Prompt | What it does | | - | - | | ***Which services have no on-call rotation configured in PagerDuty?*** | When incidents happen, it's important to have on-call information readily available to ensure a fast response time. | | ***What is the progress on my Security Initiative and what are some quick wins?*** | Surfaces real-time status for an Initiative without requesting manual updates from team members. You get an immediate picture of which entities are making progress and which are not. That visibility lets you direct support and resources to the teams that need it most. | | ***List all services with open vulnerabilities labeled CRITICAL or HIGH.*** | Helps determine which services need attention. | ### Prompts for product managers The best prompts for product managers focus on visibility, delivery health, and compliance to engineering standards that affect product velocity and quality. #### Delivery and health metrics | Prompt | What it does | | - | - | | ***Which services in the \[PRODUCT AREA] domain are failing their DORA metrics?*** | Gives quick insight into which services in that product area domain are failing DORA metrics. | #### Initiatives and adoption tracking | Prompt | What it does | | - | - | | ***Give me all currently active initiatives and ideas for how I can improve them.*** | Helps track progress on key initiatives and ensure teams are moving toward business goals. | | ***Give me links to the docs and runbooks for \[REPOSITORY].*** | Helps find the documentation for a feature's related repository. | # Cortex MCP Source: https://docs.cortex.io/get-started/cortex-ai-assistant/mcp The [Cortex MCP](https://github.com/cortexapps/cortex-mcp) is a Model Context Protocol server that brings your engineering data into the tools your team already works in, enabling natural language queries across your catalog, Scorecards, metrics, and Initiatives. It provides: * **Natural language querying** - Ask questions in plain English rather than constructing API calls directly * **Contextual awareness** - Maintains awareness of your workspace's structure when answering questions, so responses are grounded in your org's actual data * **AI-assisted insights** - Synthesizes Eng Intelligence metrics, Scorecard status, ownership, and initiative data into actionable recommendations * **Cross-tool availability** - Surfaces inside the tools your team already uses, making it an in-workflow intelligence layer rather than a standalone API * **Prompt-driven workflows** - Supports complex, multi-part queries that combine data from multiple Cortex systems in a single response * **Taking action** - Create and update entities, Scorecards, Initiatives, Workflows, and more from your MCP client, then run Workflows and check the status of each run * **Documentation querying** - The remote MCP implementation includes a `query_docs` tool that lets you ask questions against Cortex's own documentation and knowledge base in natural language ## Cortex MCP overview More of a visual learner? Watch the Cortex MCP in action in this short video. [YouTube video player](https://www.youtube.com/embed/Tjm6nwO4ByQ) # Configuring the Cortex MCP Source: https://docs.cortex.io/get-started/cortex-ai-assistant/mcp/configuring-cortex-mcp You can host the MCP server locally, or you can use a remote implementation. # Prerequisites The following are required prior to configuring the Cortex MCP: 1. Ensure that you have a compatible MCP client installed, such as [Claude Desktop](https://claude.ai/download), [Jetbrains AI Assistant](https://www.jetbrains.com/help/ai-assistant/configure-an-mcp-server.html), or [Visual Studio Code (VSCode)](https://code.visualstudio.com/docs/copilot/chat/mcp-servers). Paid subscriptions to MCP clients generally give you a larger context window, but the free versions of these clients should suffice. 2. If hosting the MCP server locally, [Docker](https://www.docker.com/) must be installed and running. 3. Create a personal access token in Cortex. See [Creating personal access tokens](/configure/settings/api-keys/personal-tokens). # Configuring the Cortex MCP Follow the steps below to configure the Cortex MCP. ## Hosting the Cortex MCP server locally Follow the steps below if the MCP server is hosted locally. ### Step 1: Installing the Cortex MCP Open terminal and run the following command: ```bash theme={null} docker pull ghcr.io/cortexapps/cortex-mcp:latest ``` ### Step 2: Configuring your MCP client > [!NOTE] > > Looking for IDE-specific setup? See the [README](https://github.com/cortexapps/cortex-mcp?tab=readme-ov-file#installation) Update your MCP client's configuration file. Make sure to include your Cortex personal access token value for the `CORTEX_API_TOKEN` argument: ```json theme={null} { "mcpServers": { "cortex": { "command": "docker", "args": [ "run", "--rm", "--pull", "always", "-i", "--env", "CORTEX_API_TOKEN=YOUR_PERSONAL_ACCESS_TOKEN_HERE", "ghcr.io/cortexapps/cortex-mcp:latest" ] } } } ``` **Alternate option: Create and configure the file in terminal** Alternatively, you could enter the following in terminal to create and configure the file: ``` export CORTEX_API_TOKEN=VALUE_OF_YOUR_PERSONAL_ACCESS_TOKEN cat << EOF > ~/Library/Application\ Support/Claude/claude_desktop_config.json { "mcpServers": { "cortex": { "command": "docker", "args": [ "run", "--pull", "always", "--rm", "-i", "--env", "CORTEX_API_TOKEN=${CORTEX_ACCESS_TOKEN}", "ghcr.io/cortexapps/cortex-mcp:latest" ] } } } EOF ``` ### Step 3: Restarting your MCP client After updating your configuration, restart your MCP client. ## Hosting the Cortex MCP server remotely The remote Cortex MCP uses the public `cortex-mcp` package as a dependency, installed from GitHub. This configuration of the Cortex MCP enables: * **Faster setup** - No need to install or maintain local binaries. * **Updated context** - Cortex automatically keeps the service aligned with the latest MCP specification. * **Secure access** - Tokens and access are managed in your Cortex workspace with security best practices. * **Seamless integration** - It works out of the box with popular MCP clients like VSCode, Claude Code, and Cursor. * **More tools** - The remote MCP implementation includes more tools, such as the `query_docs` tool that allows you to query Cortex's documentation and knowledge base in natural language. Ask questions like *How do I configure PagerDuty for my Cortex services?*, or *How can I use Cortex to drive AI maturity at my org?* It also includes the ability to add private tools and integrations on top of the public functionality. ### Choosing the remote MCP server URL for your region Use the remote MCP server URL that matches the region your Cortex workspace is hosted in: | Region | Remote MCP server URL | | - | - | | US | `https://mcp.cortex.io/mcp` | | EU | `https://mcp.eu.cortex.io/mcp` | ### Allowlisting the remote MCP server If your organization restricts network traffic, the IP addresses you need to allowlist depend on which direction the traffic flows: * **To the MCP server** - Your network restricts which destinations users can reach, or you firewall inbound access to the MCP server. Allowlist the MCP server's IP address. * **From the MCP server** - You need to permit calls the MCP server makes, such as to your Cortex workspace when it has an [IP allowlist](/configure/settings/ip-allowlist) enabled, or into your network to reach a self-hosted Jira instance, Prometheus, or a custom MCP server. Allowlist the IP addresses that Cortex sends outbound traffic from. | Region | To the MCP server | From the MCP server | | - | - | - | | US | `34.111.236.6` | `34.94.6.235`, `34.94.42.38`, and `35.236.92.1` | | EU | `136.110.164.69` | `34.140.212.3`, `34.78.206.73`, and `34.78.61.126` | The MCP server IP addresses are reserved static addresses, so they don't change. > [!WARNING] > > Don't use the MCP server's IP address to permit traffic coming from the MCP server. Outbound calls come from the IP addresses in the **From the MCP server** column, so allowlisting the MCP server's address instead causes those requests to fail with a `403` error. ### Step 1: Adding the remote MCP server to your MCP client Follow the instructions below for Claude, VSCode, or Cursor. Make sure to replace `` with the value of the personal access token you generated in Cortex. The examples below use the US server URL. If your workspace is in the EU region, replace `https://mcp.cortex.io/mcp` with `https://mcp.eu.cortex.io/mcp`. **Claude Code** Run the following command to add the Cortex remote MCP server: ``` claude mcp add --transport http cortex-remote https://mcp.cortex.io/mcp --header "Authorization: Bearer " ``` **VSCode** Add the following configuration to your `.vscode/mcp.json` file: ```json theme={null} { "servers": { "cortex": { "url": "https://mcp.cortex.io/mcp", "type": "http", "headers": { "Authorization": "Bearer " } } } } ``` For more information, see the [official VSCode documentation](https://code.visualstudio.com/docs/copilot/chat/mcp-servers). **Cursor** Add the following configuration to your Cursor settings: ```json theme={null} { "mcpServers": { "cortex": { "type": "http", "url": "https://mcp.cortex.io/mcp", "headers": { "Authorization": "Bearer " } } } } ``` ### Step 2: Validating your remote MCP configuration Validate that your remote Cortex MCP is working: * **VSCode** - Open the Command Palette and search for "MCP: List servers." Confirm that `cortex` appears as a connected server. * **Claude** - Run the command `claude mcp list` and verify that cortex-remote is in the list of servers. * **Cursor** - Open **Settings > MCP Servers** and verify that `cortex` is listed and connected. ### Step 3: Restarting your MCP client After updating your configuration, restart your MCP client. #### Self-managed additional configuration If you are a [self-managed Cortex customer](/self-managed), you must also set `CORTEX_API_BASE_URL=https://` alongside the `CORTEX_API_TOKEN` variable. **Self-managed configuration example** Set the `CORTEX_API_BASE_URL` to your backend host URL: ```json theme={null} { "mcpServers": { "cortex": { "command": "docker", "args": [ "run", "--rm", "--pull", "always", "-i", "--env", "CORTEX_API_TOKEN=YOUR_ACCESS_TOKEN_HERE", "--env", "CORTEX_API_BASE_URL=https://api.cortex.company.com", "ghcr.io/cortexapps/cortex-mcp:latest" ] } } } ``` If you are running a self-hosted instance with CA-signed certificates, you may need to mount them to the container as seen in the example below: ```json theme={null} { "mcpServers": { "cortex": { "command": "docker", "args": [ "run", "--rm", "--pull", "always", "-i", "-v", "/path/to/your//company_certs.ca:/etc/ssl/certs/company-ca.crt:ro", "--env", "REQUESTS_CA_BUNDLE=/etc/ssl/certs/company-ca.crt", "--env", "SSL_CERT_FILE=/etc/ssl/certs/company-ca.crt", "--env", "CURL_CA_BUNDLE=/etc/ssl/certs/company-ca.crt", "--env", "CORTEX_API_TOKEN=YOUR_ACCESS_TOKEN_HERE", "--env", "CORTEX_API_BASE_URL=https://api.cortex.company.com", "ghcr.io/cortexapps/cortex-mcp:latest" ] } } } ``` # Signing in to the remote Cortex MCP with OAuth Source: https://docs.cortex.io/get-started/cortex-ai-assistant/mcp/mcp-oauth Connect your MCP client to the remote Cortex MCP by logging in with your Cortex account instead of a personal access token PUBLIC BETA > [!NOTE] > > This feature is available for Cortex cloud. The remote Cortex MCP supports OAuth, so you can connect your MCP client by logging in to Cortex in your browser. You don't need to create a personal access token or add it to your client's configuration. Your MCP client handles the sign-in flow and keeps your session authorized. This page covers how to connect with OAuth. For an overview of what the Cortex MCP can do, see [Cortex MCP](/get-started/cortex-ai-assistant/mcp). To connect with a personal access token instead, see [Configuring the Cortex MCP](/get-started/cortex-ai-assistant/mcp/configuring-cortex-mcp). ## Prerequisites Before you get started: * Make sure you have an MCP client that supports remote MCP servers with OAuth, such as [Claude Code](https://docs.claude.com/en/docs/claude-code/mcp). * Have your Cortex tenant code ready. Your tenant code identifies your Cortex workspace and is part of the MCP server URL. See [Finding your tenant code](#finding-your-tenant-code) below. ### Finding your tenant code Your tenant code is the workspace name you enter in the **Enter your workspace name** field when you sign in to Cortex, e.g. `cortex-labs`. If you sign in from a bookmarked link, check the URL. Your tenant code is the value after `tenantCode=`. For example, in `https://app.getcortexapp.com/login?tenantCode=cortex-labs`, the tenant code is `cortex-labs`. > [!NOTE] > > The **Workspace name** field under **Settings > General** is the display name shown next to your logo. **It isn't your tenant code**. If you don't know your tenant code, contact your account team or Cortex support. ## Choosing your MCP server URL The OAuth-enabled MCP server URL includes your tenant code. Use the URL for the region your Cortex workspace is hosted in, and replace `` with your tenant code: | Region | MCP server URL | | - | - | | US | `https://mcp.cortex.io/t//mcp` | | EU | `https://mcp.eu.cortex.io/t//mcp` | > [!NOTE] > > These URLs are different from the token-based remote MCP URLs. Make sure to include `/t/` in the path, or the OAuth sign-in flow won't start. ## Connecting with Claude Code **1. Add the Cortex MCP server** Run the following command. If your workspace is in the EU region, use the EU URL instead. ```bash theme={null} claude mcp add --transport http --scope user cortex https://mcp.cortex.io/t//mcp ``` **2. Authenticate** Open Claude Code and run `/mcp`. Select `cortex`, then select **Authenticate**. **3. Log in to Cortex** A browser window opens to the Cortex login page. Log in to your Cortex account to authorize the connection, then return to Claude Code. To confirm the connection, run `/mcp` again and check that `cortex` shows as connected. ## Connecting with Glean > [!NOTE] > > To add the Cortex MCP server in Glean, you need the Glean Admin or MCP Server Moderator role, and you must also be a Cortex user. Glean signs in to Cortex as you to discover the available tools. To make the tools available to other users after setup, you need the Glean Admin role. **1. Add a new MCP server** In Glean, start the **+ MCP** flow to add a remote MCP server, then open the **Configuration** tab. **2. Name the server** Enter an **MCP server name** and **Description**, for example `Cortex MCP`. **3. Enter the server URL** In **MCP server URL**, enter the MCP server URL for your region, including your tenant code. Leave **Use Glean proxy** cleared unless you have trouble connecting. **4. Choose the transport and authentication** Under **Transport type**, select **Streaming HTTP**. Under **Authentication method**, select **Dynamic client registration**. Glean fills in the **Client ID** automatically. **5. Connect to Cortex** Under **Connect to server**, sign in to Cortex when prompted. When the status shows **Connected**, click **Refresh tools** to load the Cortex MCP tools. **6. Enable the tools** Under **Enable tools**, click **Edit settings** and choose which teammates can use the Cortex tools. Then click **Save**. After you enable the tools, each Glean user signs in to Cortex with their own account the first time they use a Cortex tool. Glean uses each user's own Cortex identity, not the admin's connection, so users can only see and do what their Cortex account allows. For more information, see the Glean documentation on [connecting remote MCP servers to Glean](https://docs.glean.com/administration/tools/connect-remote-mcp-servers-to-glean). ## Connecting with other MCP clients If your MCP client asks for connection details when you add a remote server, use the following settings: * **Server URL** - The MCP server URL for your region, including your tenant code. * **Transport type** - HTTP (streamable HTTP). * **Authentication** - OAuth with Dynamic Client Registration (DCR). You don't need a client ID or client secret. Your MCP client registers itself with Cortex automatically. After you add the server, start the sign-in flow from your client. A browser window opens where you log in to Cortex. > [!NOTE] > > During Public Beta, OAuth sign-in works with a set of supported MCP clients. If you have trouble connecting your client, contact your account team. ## Staying signed in After you sign in, your authentication lasts for multiple days. Your MCP client refreshes your access tokens automatically multiple times per day, so you don't need to do anything to keep your session active. When your authentication expires, sign in to Cortex again from your MCP client. In Claude Code, run `/mcp`, select `cortex`, then select **Authenticate**. ## Share your feedback Have feedback or run into issues? Reach out to your account team. # Using the Cortex MCP Source: https://docs.cortex.io/get-started/cortex-ai-assistant/mcp/using-cortex-mcp This article explains how to use the Cortex MCP. For information on setting up the Cortex MCP, refer to [Configuring the Cortex MCP](/get-started/cortex-ai-assistant/mcp/configuring-cortex-mcp). > [!TIP] > > **We'd love your feedback!**\\ > > If you're using the Cortex MCP, we'd love to hear your direct feedback on the configuration process, the tools available, and how you've been using it. Your feedback helps us improve and expand Cortex's capabilities. If you're interested in helping guide Cortex's MCP direction, [take the survey](https://forms.gle/yNLgLBrHTjKRJ34y5). ## Starting a new chat In your MCP client, ask a question about your Cortex workspace. The client uses the Cortex API to provide detailed answers based on your data. **Examples** * You might ask what's going on with a specific Scorecard. The MCP client responds with an overview, Scorecard structure information, a progress summary, and suggestions for next steps. ![Screenshot 1 of MCP example conversation](https://mintcdn.com/cortex-290c0c42/4tRxSDOxhMkPeY0E/images/mcp-scorecard.jpg?fit=max\&auto=format\&n=4tRxSDOxhMkPeY0E\&q=85\&s=eab43c778da380f351f27f268370c277) * You could ask about an entity's custom data. The MCP client responds with that entity's custom data and information about when it was created. ![Screenshot 2 of MCP example conversation](https://mintcdn.com/cortex-290c0c42/4tRxSDOxhMkPeY0E/images/mcp-custom-data.jpg?fit=max\&auto=format\&n=4tRxSDOxhMkPeY0E\&q=85\&s=571b54d5cfec6272cbbcd97961e6cb85) * You could ask about an entity's dependencies. The MCP client responds with a list of incoming and outgoing dependencies. ![Screenshot 3 of MCP example conversation](https://mintcdn.com/cortex-290c0c42/4tRxSDOxhMkPeY0E/images/mcp-dependencies.jpg?fit=max\&auto=format\&n=4tRxSDOxhMkPeY0E\&q=85\&s=7861e98735af0854bf3e5e8b75d770e1) ## Available MCP tools The Cortex MCP can use the following [Cortex REST API](/api) endpoints. Some tools read data, and others create or update data in your workspace. The Cortex MCP can't delete data. It runs bulk operations only on ownership recommendations. See [Making changes with the Cortex MCP](#making-changes-with-the-cortex-mcp). > **Catalog / Entities** > > * [searchCatalog](/api/rest/catalog-entities/search-entities) - Find entities by relevance; the primary way to search the catalog > * [listAllEntities](/api/rest/catalog-entities/list-entities) - Enumerate entities by structured filters (groups, types, owners, repos) > * [getEntityDetails](/api/rest/catalog-entities/retrieve-entity-details) - Full details for one entity: metadata, ownership, hierarchy, relationships > * [getEntityDescriptor](/api/rest/catalog-entities/retrieve-entity-descriptor) - A single entity's descriptor (optionally YAML) > * [listEntityDescriptors](/api/rest/catalog-entities/list-entity-descriptors) - List entity descriptors (optionally YAML) > * [createOrUpdateEntity](/api/rest/catalog-entities/create-or-update-entity) - Create an entity, or replace the descriptor of an existing entity > * [createOrPatchEntity](/api/rest/catalog-entities/create-or-patch-entity) - Create an entity, or update only the fields you include > * [archiveEntity](/api/rest/catalog-entities/archive-an-entity) - Archive an entity > * [unarchiveEntity](/api/rest/catalog-entities/unarchive-an-entity) - Restore an archived entity > * [listGroupsForEntity](/api/rest/groups/retrieve-groups-for-entity) - Groups assigned to an entity > * [addGroupsToEntity](/api/rest/groups/add-groups-to-entity) - Add groups to an entity > * [listDefinitions](/api/rest/entity-types/list-entity-types) - All entity types (definitions) > * [getDefinition](/api/rest/entity-types/retrieve-entity-type) - Schema and details for one entity type > * [createDefinition](/api/rest/entity-types/create-entity-type) - Create an entity type > * [updateDefinition](/api/rest/entity-types/update-entity-type) - Update an entity type > * [listCatalogPages](/api/rest/catalogs/list-catalogs) - All catalogs in your workspace > * [getCatalogPage](/api/rest/catalogs/get-catalog) - One catalog's configuration, by slug > * [upsertCatalogPage](/api/rest/catalogs/create-or-replace-a-catalog) - Create a catalog, or replace an existing one > * [getOpenApiDocForEntity](/api/rest/docs/retrieve-openapi-docs-for-entity) - OpenAPI documentation attached to an entity > * [KubernetesGetK8sResourcesForEntity](/api/rest/kubernetes-api/get-kubernetes-resource-details-for-an-entity) - Kubernetes resources linked to an entity > * [AWSGetAwsResources](/api/rest/aws-api/get-aws-resource-details-for-an-entity) - Cached Amazon Web Services (AWS) resource details for an entity > > **Additional tools** > > * `getMyWorkspace` - Enabled by default, this tool supports the "Mine" capabilities that are available in the Cortex UI. Ask questions like, "show me my Cortex entities" or "tell me how my entities are performing against the Production Readiness Scorecard." > **Custom data and events** > > * [getCustomDataForEntity](/api/rest/custom-data/list-custom-data-for-entity) - All custom key-value data for an entity > * [getCustomDataForEntityByKey](/api/rest/custom-data/retrieve-custom-data-for-entity-by-key) - One custom data value by key > * [retrieveCustomDataForEntityAdvanced](/api/rest/custom-data-advanced/retrieve-custom-data-for-entity) - Custom data across entities > * [addCustomDataForEntity](/api/rest/custom-data/add-custom-data-for-entity) - Add a custom data key-value pair to an entity > * [addCustomDataForEntityAdvanced](/api/rest/custom-data-advanced/add-custom-data-for-entity-advanced) - Add custom data to an entity, identified in the request body > * [listCustomEventsForEntity](/api/rest/custom-events/list-custom-events-for-entity) - Custom events for an entity (filter by type/time) > * [getCustomEventForEntityByUuid](/api/rest/custom-events/retrieve-custom-event-by-uuid) - One custom event by UUID > * [createCustomEventForEntity](/api/rest/custom-events/create-custom-event-for-entity) - Add a custom event to an entity > * [replaceCustomEventForEntityByUuid](/api/rest/custom-events/update-custom-event-by-uuid) - Update a custom event by UUID > **Dependencies and relationships** > > * [listDependenciesForEntity](/api/rest/dependencies/retrieve-all-dependencies-for-an-entity) - Incoming + outgoing dependencies (blast radius) > * [getDependency](/api/rest/dependencies/retrieve-dependency-between-entities) - Details of one dependency between two entities > * [createDependency](/api/rest/dependencies/create-dependency-from-entity) - Create a dependency between two entities > * [updateDependency](/api/rest/dependencies/update-dependency-between-entities) - Update a dependency between two entities > * [listRelationshipTypes](/api/rest/entity-relationship-types/list-relationship-types) - All relationship types > * [getRelationshipTypeDetails](/api/rest/entity-relationship-types/get-a-relationship-type) - Config/rules for one relationship type > * [createRelationshipType](/api/rest/entity-relationship-types/create-relationship-type) - Create a relationship type > * [updateRelationshipType](/api/rest/entity-relationship-types/update-relationship-type) - Update a relationship type > * [listEntityRelationships](/api/rest/entity-relationships/list-entity-relationships-for-a-relationship-type) - Full org graph for a relationship type > * [listEntitySourcesForRelationshipType](/api/rest/entity-relationships/list-entity-sources-for-a-relationship-type) - Sources for a relationship type & entity > * [listEntityDestinationsForRelationshipType](/api/rest/entity-relationships/list-entity-destinations-for-a-relationship-type) - Destinations for a relationship type & entity > **Scorecards** > > * [listScorecards](/api/rest/scorecards/list-scorecards) - All scorecards (filter by group/entity/team) > * [getScorecard](/api/rest/scorecards/retrieve-scorecard) - Full scorecard config, rules, levels, weights > * [createOrUpdateScorecard](/api/rest/scorecards/create-or-update-scorecard) - Create a Scorecard from a YAML descriptor, or replace the Scorecard that has the same tag > * [listScorecardScores](/api/rest/scorecards/retrieve-scorecard-scores) - Scores for all entities on a scorecard > * [listScorecardScoresForEntity](/api/rest/catalog-entities/retrieve-entity-scorecard-scores) - An entity's scores across all Scorecards > * [refreshScorecardScoreForEntity](/api/rest/scorecards/evaluate-entity-scorecard-score) - Re-evaluate an entity's score on a Scorecard > * [getScorecardNextStepsForEntity](/api/rest/scorecards/retrieve-next-steps-for-entity-in-scorecard) - Steps to reach an entity's next maturity level > * [listScorecardRuleExemptions](/api/rest/scorecards/list-scorecard-rule-exemptions) - Rule exemptions across Scorecards, with status, requester, approver, and expiry > * [requestScorecardRuleExemption](/api/rest/scorecards/request-scorecard-rule-exemption) - Request a rule exemption for an entity > * [approveScorecardRuleExemption](/api/rest/scorecards/approve-scorecard-rule-exemption) - Approve a pending rule exemption > * [denyScorecardRuleExemption](/api/rest/scorecards/deny-scorecard-rule-exemption) - Deny a pending rule exemption > * [revokeScorecardRuleExemption](/api/rest/scorecards/revoke-scorecard-rule-exemption) - Revoke an approved rule exemption > **Initiatives** > > * [listInitiatives](/api/rest/initiatives/list-initiatives) - All initiatives (optional draft/expired) > * [getInitiative](/api/rest/initiatives/get-initiative) - One initiative's goals, timeline, targets, progress > * [createInitiative](/api/rest/initiatives/create-an-initiative) - Create an Initiative > * [updateInitiative](/api/rest/initiatives/update-an-initiative) - Update an Initiative > **Verifications** > > * [listVerifications](/api/rest/verifications/retrieve-verifications) - Entity verifications across your workspace > * [listVerificationPeriods](/api/rest/verifications/retrieve-verification-periods) - All verification periods > * [retrieveVerificationPeriod](/api/rest/verifications/retrieve-a-verification-period) - Details for one verification period > * [createVerificationPeriod](/api/rest/verifications/create-a-verification-period) - Create a verification period > * [updateVerificationPeriod](/api/rest/verifications/update-a-verification-period) - Update a verification period > * [listVerificationsForEntity](/api/rest/catalog-entities/retrieve-entity-verifications) - Verification history for an entity > * [verifyEntityForPeriod](/api/rest/catalog-entities/verify-an-entity-for-a-verification-period) - Verify one entity for a verification period > **Metrics** > > * [getCustomMetricData](/api/rest/custom-metrics/retrieve-custom-metrics-data-points) - Custom metric time-series for an entity > * [createCustomMetricData](/api/rest/custom-metrics/add-custom-metrics-data-point) - Add a single custom metric data point for an entity > * [listCustomMetricDefinitions](/api/rest/custom-metrics/list-custom-metric-definitions) - Custom metric definitions in your workspace > * [getCustomMetricDefinition](/api/rest/custom-metrics/retrieve-a-custom-metric-definition) - A single custom metric definition by key > * [createCustomMetricDefinition](/api/rest/custom-metrics/create-a-custom-metric-definition) - Define a new API custom metric > * [updateCustomMetricDefinition](/api/rest/custom-metrics/update-a-custom-metric-definition) - Replace the definition of an API custom metric > * [queryTraceEvents](/api/rest/eng-intel-trace/query-raw-trace-events-from-engineering-data-sources) - Individual Eng Intelligence event records (filter, sort, paginate) > > **Additional tools** > > * `listMetricDefinitions` - This tool returns the Eng Intelligence metrics available in your workspace, along with the metadata needed to query them. Ask questions like, "which engineering metrics can I ask about?" or "what deployment data is available in Eng Intelligence?" > * `queryPointInTimeMetrics` - This tool returns current values for one or more Eng Intelligence metrics, with optional comparisons against a previous period and grouping by team, entity, or user. Ask questions like, "what's our deployment frequency this quarter compared to last?" or "show me change failure rate by team for the last 30 days." > **Teams and on-call** > > * [getTeamDetails](/api/rest/teams/retrieve-team-details) - Team members, Slack channels, metadata > * [updateCortexTeamMembers](/api/rest/teams/\[cortex-managed-teams]-update-members-in-team) - Update the members of a Cortex-managed team > * [archiveTeam](/api/rest/teams/archive-team) - Archive a team > * [unarchiveTeam](/api/rest/teams/unarchive-team) - Restore an archived team > * `listTeamMemberRoles` - All team member roles in your workspace > * `createTeamMemberRole` - Create a team member role > * [getTeamHierarchyRelationships](/api/rest/team-hierarchies/retrieve-team-relationships) - Parent and child relationships between teams > * [getCurrentOncallForEntity](/api/rest/on-call/retrieve-current-on-call-for-entity) - Real-time on-call for an entity > **Ownership recommendations** > > * [listOwnershipRecommendations](/api/rest/recommendations/list-ownership-recommendations) - Team ownership recommendations for entities, strongest first, filtered by entity, team, confidence, or status > * [listOwnershipRecommendationEntities](/api/rest/recommendations/list-entities-with-ownership-recommendations) - Entities that have ownership recommendations, with the number of open recommendations for each > * [acceptOwnershipRecommendation](/api/rest/recommendations/accept-an-ownership-recommendation) - Add the recommended team as an owner of the entity > * [batchAcceptOwnershipRecommendations](/api/rest/recommendations/accept-many-ownership-recommendations) - Accept many recommendations in one request > * [rejectOwnershipRecommendation](/api/rest/recommendations/reject-an-ownership-recommendation) - Hide a recommendation from the open list > * [batchRejectOwnershipRecommendations](/api/rest/recommendations/reject-many-ownership-recommendations) - Reject many recommendations in one request > * [restoreOwnershipRecommendation](/api/rest/recommendations/restore-an-ownership-recommendation) - Open a rejected recommendation again > * [batchRestoreOwnershipRecommendations](/api/rest/recommendations/restore-many-ownership-recommendations) - Restore many recommendations in one request > **Deploys** > > * [getDeploysForEntity](/api/rest/deploys/list-deployments-for-entity) - Deployment history for an entity > * [searchDeploys](/api/rest/deploys/search-deployments-across-the-tenant) - Search deployments across all entities > * [listDeployEnvironments](/api/rest/deploys/list-all-distinct-deploy-environments-for-this-tenant) - All deploy environments in your workspace > * [addDeployForEntity](/api/rest/deploys/add-deployment-for-entity) - Add a deploy to an entity > * [updateDeployByUuid](/api/rest/deploys/update-deployment-by-uuid) - Update a deploy by UUID > **Workflows** > > * [listWorkflows](/api/rest/workflows/list-workflows) - All Workflows > * [getWorkflow](/api/rest/workflows/retrieve-workflow) - One Workflow's configuration and actions > * [validateWorkflowDescriptor](/api/rest/workflows/validates-yaml-descriptor) - Check a Workflow's YAML descriptor for errors before you save it > * [createOrUpdateWorkflow](/api/rest/workflows/create-or-update-workflow) - Create a Workflow, or replace the Workflow that has the same tag. Requires the `Edit Workflows` permission. > * [runWorkflow](/api/rest/workflows/run-a-workflow) - Start a run of a Workflow. Requires the `Execute Workflow Runs` permission. > * [getWorkflowRun](/api/rest/workflows/get-workflow-run-details) - One Workflow run, including the outcome of each action > * [listWorkflowRuns](/api/rest/workflows/list-workflow-runs) - Workflow runs from the last 30 days, with filters and pagination > **Plugins** > > * [listAllPlugins](/api/rest/plugins/get-all-plugins) - All plugins in your workspace > * [getPluginByTag](/api/rest/plugins/get-plugin-by-tag) - One plugin's configuration > * [createPlugin](/api/rest/plugins/create-a-plugin) - Create a plugin > * [updatePlugin](/api/rest/plugins/replace-a-plugin) - Replace a plugin's full configuration > * `patchPlugin` - Update only the plugin fields you include > **Scaffolder** > > * [listScaffolders](/api/rest/scaffolder/list-scaffolder-templates) - All Scaffolder templates > * [getScaffolder](/api/rest/scaffolder/retrieve-scaffolder-template) - One Scaffolder template's configuration > * [createOrUpdateScaffolder](/api/rest/scaffolder/create-or-update-scaffolder-template) - Create a Scaffolder template, or replace an existing one > * [updateScaffolder](/api/rest/scaffolder/update-scaffolder-template) - Update a Scaffolder template > **CQL queries** > > * [createQuery](/api/rest/queries/run-query) - Run a CQL query across your entities. This doesn't change any data. > * [getQueryResults](/api/rest/queries/retrieve-query-results) - Results of a CQL query you ran > **Packages** > > Upload a dependency manifest or lockfile to record an entity's packages: > > * [uploadJavaPackage](/api/rest/packages/\[java]-upload-single-java-package) - A single Java package > * [uploadMavenPom](/api/rest/packages/\[java]-upload-maven-pomxml) - Maven `pom.xml` > * [uploadNpmPackageJson](/api/rest/packages/\[js]-upload-npmyarnpnpm-packagejson) - npm, Yarn, or pnpm `package.json` > * [uploadNpmPackageLockJson](/api/rest/packages/\[js]-upload-npm-package-lockjson) - npm `package-lock.json` > * [uploadPnpmLock](/api/rest/packages/\[js]-upload-pnpm-lockyaml) - `pnpm-lock.yaml` > * [uploadYarnLock](/api/rest/packages/\[js]-upload-yarnlock) - `yarn.lock` > * [uploadPipfileLock](/api/rest/packages/\[python]-upload-pipfilelock) - `Pipfile.lock` > * [uploadRequirementsTxt](/api/rest/packages/\[python]-upload-requirementstxt) - `requirements.txt` > * [uploadGoSumPackage](/api/rest/packages/\[golang]-upload-gosum) - `go.sum` > * [uploadNugetCsproj](/api/rest/packages/\[csharp]-upload-nuget-csproj) - NuGet `.csproj` > * [uploadNugetPackagesLock](/api/rest/packages/\[csharp]-upload-nuget-packageslockjson) - NuGet `packages.lock.json` > * `uploadNugetPackagesConfig` - NuGet `packages.config` > **Docs and meta** > > * [listIntegrationStatuses](/api/rest/integration-status/list-installed-integrations-and-their-status) - Installed integrations and the result of each one's most recent connection check > * `query_docs` - This tool queries the Cortex help center. > * `get_more_tools` - This tool discovers additional specialized tools. ## Enabling and disabling provided tools Before submitting questions or commands, you may want to limit the number of provided tools being used by the MCP provider. For example, you might want to use the MCP to ask about entities, but you don't want to allow questions about Scorecards. If you want the Cortex MCP to stay read-only, turn off the tools that create, update, archive, upload, approve, or run something. Read tools generally start with `get`, `list`, `search`, `retrieve`, or `query`. `createQuery` runs a CQL query without changing data, so you can leave it on. **Example** In the settings of your MCP client, it's possible to limit which Cortex tools are being used. For example, in Claude desktop: 1. Navigate to **Settings > Connectors > Cortex > 3 dots icon > Tools and Settings**. 2. Below **Provided Tools**, toggle off the options you don't need. 3. Restart Claude. 4. Navigate to your Claude chat and enter commands. ## Eng Intelligence metrics in the Cortex MCP [Eng Intelligence](/improve/eng-intelligence) metrics are also available to Cortex MCP. This brings metric data directly into the Cortex MCP, enabling richer AI-assisted insights, not only into engineering performance, but across your entire Cortex ecosystem. It allows you to be a more proactive leader and enables more data-driven planning sessions. ### Querying Eng Intelligence metrics in the Cortex MCP Ensure you have the latest Cortex MCP version configured in your environment. Once enabled, the MCP automatically includes endpoints for Eng Intelligence metrics. You can then query Eng Intelligence metrics alongside ownership, Scorecard, and Initiative information. For example: * ***Evaluate my DORA metric performance in Q3. Highlight where the team is performing well and bring areas of improvement to my attention.*** * ***Which services have concerning MTTR trends, and what scorecard gaps are contributing?*** * ***Recommend initiatives and scorecard changes I could consider to address my upward trend in incidents.*** * ***Review last quarter’s performance against our goals, identify the top three bottlenecks, and suggest changes to our scorecards to address them.*** * ***Is there a correlation between my PR size and how fast we ship?*** ## Making changes with the Cortex MCP In addition to answering questions, the Cortex MCP can create and update data in your workspace. For example, you can ask your client to create an Initiative, record a deploy for an entity, or request a Scorecard rule exemption. See [Available MCP tools](#available-mcp-tools) for the full list. ### Prerequisites * The Cortex MCP acts as the user who owns your personal access token. It can only make changes that user has [permission](/configure/settings/managing-users/permissioning) to make in Cortex. * Make sure you're using the latest version of the Cortex MCP. If you host it locally, pull the latest `ghcr.io/cortexapps/cortex-mcp:latest` image. ### Example prompts * ***Create an Initiative that asks every service in the Payments group to reach Gold on the Production Readiness Scorecard by March 31, 2027.*** * ***Add a deploy to the `payments-api` entity for version 2.4.1 in the production environment.*** * ***Request an exemption from the "Has a runbook" rule on the Production Readiness Scorecard for `legacy-billing`. It's being retired this quarter.*** * ***Archive the `old-search` entity.*** * ***Add `tier: 1` as custom data on the `checkout` entity.*** ### What the Cortex MCP can't do * **Delete data.** To protect your data from accidental removal, no delete endpoints are available through the Cortex MCP. This includes deleting custom data, deploys, and custom events. Delete data in Cortex or with the [Cortex REST API](/api/rest/custom-data/delete-custom-data-for-entity) instead. See [Deleting custom data](/ingesting-data-into-cortex/entities-overview/entities/custom-data#deleting-custom-data) for more information. * **Run bulk operations.** Endpoints that change many records at once aren't available, except the endpoints that accept, reject, or restore many ownership recommendations. This includes adding custom data, dependencies, or custom metric data points in bulk, verifying entities in bulk, uploading multiple Java packages at once, and replacing all team hierarchy relationships. Make these changes in Cortex or with the REST API. * **Create teams, edit team details, or change relationships and OpenAPI docs.** The Cortex MCP can't create a team, update a team's details, add or update an entity's relationship sources and destinations, or update an entity's OpenAPI documentation. Make these changes in Cortex or with the REST API. * **Manage workspace administration.** Integration configurations, API keys, users, and workspace settings aren't available through the Cortex MCP. ### Things to know * Some tools create a new object or replace an existing one that has the same tag: `createOrUpdateEntity`, `createOrUpdateScorecard`, `createOrUpdateScaffolder`, `upsertCatalogPage`, and `updatePlugin`. If you aren't sure whether the tag is already in use, ask your client to look it up first. * To change only some fields on an entity or plugin, ask your client to use `createOrPatchEntity` or `patchPlugin`, which leave everything else as is. * Archiving is reversible. Use `unarchiveEntity` or `unarchiveTeam` to restore an archived entity or team. * Many MCP clients ask you to approve each tool call. Check the details before you approve a change. ## Creating and running Workflows with the Cortex MCP You can use the Cortex MCP to create, update, and run [Workflows](/streamline/workflows) without leaving your MCP client. For example, you can ask your client to build a Workflow from a description, start a run, and then check on the run until it finishes. ### Prerequisites * To create or update a Workflow, the user who owns your personal access token needs the `Edit Workflows` [permission](/configure/settings/managing-users/permissioning). * To run a Workflow, the user needs the `Execute Workflow Runs` permission. The Viewer role doesn't include this permission. * The Workflow must be published (not a draft) and have **Runnable via API** turned on. See [Enabling API access](/streamline/workflows/publishing-a-workflow#enabling-api-access). If a Workflow doesn't meet these requirements, the MCP client tells you what's blocking the run, so you can fix it in Cortex and try again. ### Example prompts * ***Run the "Provision staging database" Workflow.*** * ***Run the "Rotate service credentials" Workflow for the `payments-api` entity, then tell me when it finishes.*** * ***Create a Workflow that posts a message to the #deploys Slack channel, and make it runnable via API.*** * ***Show me the runs of the "Onboard new service" Workflow from the last week. Did any of them fail?*** ### Things to know * `createOrUpdateWorkflow` replaces any existing Workflow that has the same tag. Ask your client to look up the Workflow first if you aren't sure the tag is unique. * When you run a Workflow for a specific entity, include the entity in your prompt. A Workflow scoped to an entity can't run without one. * By default, run results returned to the MCP leave out the run context (for example, secret names and the entity descriptor) to keep responses short. To get the context, ask your client to include it. * `listWorkflowRuns` returns runs from the last 30 days. * You can't delete Workflows through the Cortex MCP. Delete them in Cortex instead. ## Crafting effective MCP prompts The Cortex MCP becomes more powerful when using it becomes second nature to your teams. That shift happens when you have developed prompts that fit your specific role, answer your recurring questions, and surface information in the exact moments you need it. Refer to the [Cortex MCP Prompt Library](/get-started/cortex-ai-assistant/library) for more information. ## Troubleshooting and FAQ See frequently asked questions below. > **When I ask a question in my MCP client, why do I see an error that says I hit the max length for this chat?** > > This can happen if you're on the free plan of your MCP client. > **Can I make changes via the Cortex MCP?** > > Yes. The Cortex MCP can create and update many kinds of data, such as entities, Scorecards, Initiatives, and Workflows, if the user who owns your personal access token has the required permissions. It can't delete data or run bulk operations. See [Making changes with the Cortex MCP](#making-changes-with-the-cortex-mcp). > **How do I resolve "unauthorized" errors in the MCP?** > > Ensure the value of your Cortex API token is valid in your configuration. > **How do I resolve "file not found" errors in the MCP?** > > Ensure your OpenAPI spec path is correct when mounting. > **How do I resolve connection issues with the MCP?** > > Verify your Cortex API endpoint is accessible. > **How do I resolve a 403 forbidden error in the remote MCP?** > > Ensure that you set up the remote MCP with a [personal access token](/configure/settings/api-keys/personal-tokens) generated in Cortex. Remote MCP setup requires a personal access token, not an API key. > **Why do I see an SSL certificate error while using the MCP?** > > This is most likely caused by an issue within your network. It's recommended to contact your organization's infrastructure or security team to troubleshoot. # Cortex quick start guide Source: https://docs.cortex.io/get-started/quickstart This guide walks you through Cortex's core concepts and initial setup. By the end, you'll understand how Cortex works and how to start using it. ## **Welcome to Cortex!** Cortex is an Engineering Operations Platform (EngOps) that brings your entire engineering ecosystem into a single, trusted source of truth. Instead of hunting through spreadsheets, wikis, and a dozen disconnected tools to answer basic questions like, "who owns this service?", "is it production-ready?", or "what depends on it?", your team gets the answers at a glance, always up to date. Under the hood, Cortex continuously polls your existing tools and stitches that data into a unified model of your software. On top of that model, you can define standards, automate self-service actions, and give every engineer the context they need to ship reliable software faster. ## The building blocks Before you begin, take a minute to get familiar with the core Cortex concepts. They're the foundation for everything in this guide and everything that comes after. ## Entities An entity is anything in your engineering world that you want to track. Most commonly, that means services and the infrastructure they run on, but entities can also represent teams, domains, APIs, pipelines, ML models, or any other construct that matters to how you build software. Entities can own other entities, depend on each other, and roll up into higher-level groupings—which is what turns a flat list of components into a real map of your architecture. ## Catalogs A catalog is a curated view of your entities, defined by entity type, i.e. service, domain, or team. It's searchable, filterable, and browsable, serving as the home base your developers return to every day to see what exists, who owns it, and how healthy it is. As you add entities and turn on integrations, your catalog fills in automatically, becoming the foundation for everything else Cortex offers: Scorecards, self-service actions, and AI-powered insights. ## Scorecards A scorecard is how you define and enforce quality standards across your entities. You set the rules (what "good" looks like), organize them into levels (bronze, silver, gold, or whatever progression fits), and Cortex continuously evaluates each entity against them. The result is a clear, always-current score for things like production readiness, security posture, or operational maturity. ## Initiatives An initiative is a focused, time-bound campaign for rolling out a specific improvement across your entities. You define the goal, e.g. *Migrate all services to Kubernetes by Q3*, scope it to the right entities, and set a deadline. Cortex tracks progress automatically, surfaces what's still outstanding, and keeps the right owners accountable. ## Relationships / Dependencies Relationships capture how your entities connect to one another, turning a flat list of components into a real map of your architecture. Some relationships are implicit and created automatically, like the hierarchy between domains, teams, and services, or the dependencies between services. Others are generic relationships that you configure to reflect the connections that matter to your organization, whether that's "calls", "stores data in", "deployed by", or anything else. ## Entity descriptor (YAML) Every entity in Cortex is backed by a YAML descriptor—a single file that captures its metadata, ownership, and context. Each `x-cortex-*` block defines a specific piece of information: owners, links to dashboards or runbooks, Slack channels, custom metadata, and more. You can edit descriptors directly in the Cortex UI, or manage them in your own repositories and sync them via GitOps—whichever fits your team's workflow. ## Integrations Integrations are the connections between Cortex and the tools your team already uses—GitHub, PagerDuty, Datadog, Jira, your cloud provider, and so on. Each integration pulls live data into Cortex and attaches it to the right entity automatically. A service in the catalog isn’t just a name; it’s a rich, current view of its on-call rotation, deployment history, open incidents, documentation, and dependencies. ## Custom data Custom data is how you extend Cortex with information specific to your organization. It includes user-defined metadata (any key-value context you want to track), audit trails that record how entities change over time, and operational health metrics like deploy frequency, lead time, and other indicators of how your software is actually performing. If the out-of-the-box integrations don't capture what your team needs, custom data fills the gap. # Building on the foundation: Catalogs, Scorecards, Workflows, and Eng Intelligence Source: https://docs.cortex.io/get-started/quickstart/building-on-the-foundation-catalogs-scorecards-workflows-and-eng-intelligence With your foundation in place, it's time to put Cortex to work. This article covers the core features your team will use every day and how they turn your connected data into real visibility, accountability, and action. ## Working with the catalog A [catalog](/ingesting-data-into-cortex/catalogs) is a defined selection of entities you use to track the components of your infrastructure—services, domains, cloud resources, and more. Entities are defined in YAML, but catalogs are created in the Cortex UI and act like filters that group related entities together. A single entity can belong to multiple catalogs. Cortex includes four built-in catalogs: Services, Infrastructure (with AWS, Azure, and Google Cloud resources pulled in automatically), Domains (displayed hierarchically), and Teams (displayed hierarchically with a Scorecard leaderboard). You can rename the defaults or create custom catalogs to match your organization's structure. ## Understanding Scorecards [Scorecards](/standardize/scorecards) are how you establish and enforce standards across your entities—whether that's defining best practices, tracking migrations, promoting accountability, standardizing configuration, or setting maturity benchmarks. Each Scorecard evaluates entities against a set of rules, which can reference metadata within Cortex or pull data from third-party integrations. Levels and points add a layer of gamification, giving developers clear, incremental goals. Scorecards are designed for ongoing standards, not time-bound pushes. When you need to hit a specific deadline, create an [Initiative](/improve/initiatives) to drive focused progress by a target date. ## Reports Use reporting in Cortex to track how entities perform against Scorecards, analyze Scorecard trends over time, and surface the areas that need attention. Reports apply to published Scorecards in your workspace. See [Reports](/improve/reports) for more information. Cortex offers several built-in reports out of the box: Executive, All Scorecards, Bird's Eye, Progress, and Report Card. ## Using Workflows Engineering teams use [Workflows](/streamline/workflows) when they need to standardize and automate high-stakes operations like service creation, access provisioning, or incident response, especially when those processes involve multiple tools, people, or approval steps. They're also useful for onboarding, where repeatability and speed matter. ## Leveraging Eng Intelligence [Eng Intelligence](/improve/eng-intelligence) gives engineering leaders a clear, data-driven view of how their organization builds and ships software. Surface bottlenecks in the pull request lifecycle, measure incident response, understand cross-team activity, and identify where to dig deeper. Eng Intelligence in Cortex includes: * Dashboards * [DORA Dashboard](/improve/eng-intelligence/dora-dashboard) - The speed, reliability, and efficiency of your development practices at a glance * [Velocity Dashboard](/improve/eng-intelligence/velocity-dashboard) - Team progress across the software development lifecycle * [AI impact for GitHub Copilot Dashboard](/improve/eng-intelligence/dashboards/ai-impact) - Copilot adoption and engagement across engineering * [Custom Dashboards](/improve/eng-intelligence/dashboards/custom) - Shared views tailored to the metrics your organization cares about most * [Data Explorer](/improve/eng-intelligence/data-explorer) - Explore trends over time and drill into the underlying data, covering deploys, version control, project management (Jira), and incident management (PagerDuty) * [Custom metrics](/improve/eng-intelligence/custom-metrics) - Define your own time series metrics to power Eng Intelligence analytics, drawing from your Cortex integrations or internal data sources # Getting started: Logging in to Cortex and configuring your workspace Source: https://docs.cortex.io/get-started/quickstart/getting-started-logging-in-to-cortex-and-configuring-your-workspace This article walks through logging in to Cortex for the first time. It also includes additional information for admins on how to configure the Cortex workspace. ## Logging in to Cortex > [!NOTE] > > On-prem users log in through their organization's unique URL, e.g. `https://app.cortex.your-org-name.com`. Check with your Cortex admin if you don't know your URL. Follow the steps below to log in to Cortex Cloud. 1. Go to the Cortex login page: 1. US environment - [https://app.getcortexapp.com/login](https://app.getcortexapp.com/login) 2. EU environment - [https://app.eu.cortex.io/login](https://app.eu.cortex.io/login) 2. Enter your workspace name, then click **Sign in**. When you first log in to your Cortex workspace, you are prompted through the steps of configuring your account and connecting data. See the video below for a demonstration: [YouTube video player](https://www.youtube.com/embed/yT6Ka0y_r80) > [!NOTE] > > Once Cortex detects a user's workspace, it automatically redirects them to their SSO provider and preserves any deep links, so they land exactly where they intended without any extra steps. ### Session timeouts Cortex sessions expire after **7 days of inactivity**. Inactivity is defined as not having made a request in the past 7 days. Active usage resets the timer, so users only need to re-authenticate after a continuous period without activity. **How it works** When a user authenticates, Cortex creates a session that remains active as long as the user continues to make requests. After 7 days without activity, the session expires and the user must re-authenticate. This behavior is the same for both Cloud and On-Prem deployments. The only difference between the two is the authentication method: * **Cloud** (US and EU) - Authentication goes through Auth0 + OIDC. * **On-Prem** - Authentication uses OIDC directly. **Logging out** When a user logs out from the UI, Cortex clears the session and cookie, then redirects them to the login page. > [!NOTE] > > The session timeout is a global configuration value and cannot currently be customized per tenant. ## For Cortex Admins Users with the `Admin` role have full access to everything in Cortex, from customizing the organization's workspace and setting up SSO to managing users and configuring entities. This section covers the essentials for getting your workspace set up and ready for your team. > [!NOTE] > > Access your Cortex workspace using the workspace ID provided to you by the Cortex team. If you are deploying Cortex on-premises, the Cortex team will provide you with access to an installer. ### Setting up SSO Your initial login is configured to use Google for Single Sign-On (SSO). If you do not use a Google domain email address, contact the Cortex team at [help@cortex.io](mailto:help@cortex.io) to discuss initial access and [configuring an alternate SSO provider](/configure/settings/managing-users/configuring-sso). ### Customizing the look of your workspace A few quick tweaks to your workspace can help make it feel like part of your company's toolkit. Head to general settings to upload your logo, set a workspace name, and choose a brand color. See [Customizing your workspace](/configure/settings/workspace-customization) for more information. ### Adding users to your workspace With your account set up, you're ready to bring your team into Cortex. You can invite users one at a time or in bulk, and assign each person a role that reflects the level of access they need. See [Roles and permissions](/configure/settings/managing-users/permissioning) for more information. Before you start inviting the broader team, it's strongly recommended to configure at least two users with the `Admin` role. Having a second admin ensures redundancy of access: if one admin is out of office, changes roles, or leaves the organization, you'll always have someone who can manage Cortex. ### Additional resources Go further with your initial setup! We recommend reviewing the following resources: * [Onboarding management](/configure/settings/managing-users/onboarding-mgmt) - Stay informed about user onboarding statuses. * [IP allowlist](/configure/settings/ip-allowlist) - Use the IP allowlist to restrict which networks can access your Cortex workspace. * [Workspace settings](/configure/settings) - Further customize your Cortex workspace and view audit logs. # Going further with Cortex Source: https://docs.cortex.io/get-started/quickstart/going-further-with-cortex With the foundation laid and the core features in place, you're ready to take Cortex further. This article covers the capabilities that help you tailor Cortex to your organization. ## Tracking ownership with teams In Cortex, teams play two roles: they're entities that represent your organization, and they're the owners of entities in your catalogs. Ownership is central to how Cortex works as organizations rely on it to establish clear accountability for services, data, and everything else in the catalog. It also determines who receives notifications from Cortex, including on-call changes, Scorecard updates, and other alerts. Like other [entities](/ingesting-data-into-cortex/entities-overview/entities), teams can be evaluated with [Scorecards](/standardize/scorecards), enriched by [integrations](/ingesting-data-into-cortex/integrations), and extended with [custom data](/ingesting-data-into-cortex/entities-overview/entities/custom-data). They can be organized into hierarchies, and their activity can be tracked and analyzed in [Eng Intelligence](/improve/eng-intelligence). You can create teams manually in Cortex or pull them in automatically from your integrations. ## Building your own plugin When Cortex doesn't have exactly what you need out of the box, [plugins](/streamline/plugins) let you build it yourself. Use them to support custom workflows, surface data from internal systems, or connect tools Cortex doesn't natively integrate with. Each plugin is a single HTML file rendered inside an iframe within Cortex. Plugin proxies handle CORS restrictions and can add custom headers and secrets to outbound requests, making it easy to work with external APIs. Plugins also get contextual information about where they're running in the app, so they can adapt what they show. ## Managing external docs Documentation is often one of the biggest pain points in a growing engineering org—scattered across wikis, Google Docs, repos, and shared drives, with no easy way to tell what's current or relevant. Cortex solves this by becoming the source of truth for your external docs. You can aggregate documentation onto the entities it relates to, so a service's runbook, architecture notes, and onboarding guide all live right next to its ownership and health information. See [Adding external documentation](/ingesting-data-into-cortex/entities-overview/entities/external-docs) for more information. ## Using GitOps with Cortex Instead of managing everything through the Cortex UI, you can take a [GitOps approach](/configure/gitops). GitOps is a practice that treats configuration the same way engineering teams already treat code: stored in a Git repository, reviewed through pull requests, and deployed automatically when changes are merged. Applied to Cortex, that means your entities, Scorecards, and Workflows are defined as descriptor files in a repo you own. When someone opens a PR to update a descriptor, your team reviews it like any other change; once it's merged, Cortex picks it up and syncs the update automatically. This approach offers several advantages: * **Version-controlled metadata** - Every change has history, context, and an author. * **A single source of truth** - The repository where your code lives also holds the definitions of how that code is represented in Cortex. * **Full ownership of your data** - Descriptors live in your repository, not locked inside the UI. * **Clear auditability** - GitOps logs let you monitor and track every sync, making it easy to debug issues or review changes. ## Querying your Cortex data with AI Cortex puts your engineering data within reach through natural-language questions, so you can pull answers from the tools you already work in instead of clicking through the UI. Ask about services, ownership, Scorecards, Initiatives, incidents, deployments, and more—all in plain language. You can reach it two ways: * Via the [AI Assistant in Slack](/get-started/cortex-ai-assistant) (mention `@Cortex` in any channel or DM) * Through your own [AI tools via MCP](/get-started/cortex-ai-assistant/mcp) Either way, responses are based on your actual Cortex data and honor each person's individual permissions. # Laying the foundation: Data modeling, integrations, and identity mapping Source: https://docs.cortex.io/get-started/quickstart/laying-the-foundation-data-modeling-integrations-and-identity-mapping Before you can get the most out of Cortex, a few foundational pieces need to be in place. This article walks through planning your data model, configuring your first integrations, and mapping user identities across tools—the groundwork that makes everything else in Cortex work smoothly. ## Data modeling Your data model is the foundation of everything else in Cortex, so it's worth planning before you start importing entities. Think about which parts of your engineering ecosystem you want to represent, how they relate to one another, and how different teams will want to slice and view them. * Identify the key entities you want to represent in your catalogs. See [Managing entities](/ingesting-data-into-cortex/entities-overview/entities) for a rundown of the default entity types. * Create [custom entity types](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/entity-types) if the defaults don't fit your use case. * [Set up catalogs](/ingesting-data-into-cortex/catalogs) to organize the entities that make up your infrastructure. ## Integrating your tools with Cortex As you integrate your tools with Cortex, it's also possible to streamline work during an incident, efficiently track issues, monitor your code for vulnerabilities, and more. See the [full list of available integrations](/ingesting-data-into-cortex/integrations). Cortex meets your team where they already work, with integrations across version control, project management, on-call, communication, infrastructure, security, issue tracking, code quality, and beyond. ## Configuring identity mappings and reviewing mapped services [Identity mappings](/configure/settings/managing-users/identity-mapping) connect accounts from your integrations to the right Cortex users by matching on name or email. This keeps integrations working correctly for each team member and ensures features like the Developer Homepage and Eng Intelligence show the right data for the right people. Cortex handles most matches automatically, but when account details differ across tools, admins can review and map users manually under **Settings > Identity mappings**. ## Reviewing mapped services Cortex recommends connections for your services. For example, if you connected PagerDuty, Slack, and Jira, then Cortex will recommend an entity's on-call service, Slack channel, and Jira project. You can change these details before confirmation. # Cookbooks Source: https://docs.cortex.io/guides Proven, step-by-step guides for getting real work done in Cortex Cookbooks help you go from "how do I do this?" to done. Each one is organized by product area and packed with recipes—short, step-by-step guides for the tasks teams tackle most in Cortex. > **[Scorecards](/guides/product-areas/scorecards)** > > Recipes for building and managing Scorecards > **[Workflows](/guides/product-areas/workflows)** > > Recipes for automating tasks with Workflows > **[Eng Intelligence](/guides/product-areas/eng-intelligence)** > > Recipes for tracking and improving engineering performance with Eng Intelligence > **[Data verification](/guides/product-areas/data-verification)** > > Recipes for keeping your catalog data accurate with data verification > **[Plugins](/guides/product-areas/plugins)** > > Recipes for extending Cortex with custom plugins # Establish consistent AI security controls Source: https://docs.cortex.io/guides/ai-excellence/establish-consistent-ai-security-controls Organizations often experience pain points around AI practices where AI models or pipelines live in isolated repositories, security and compliance requirements are inconsistently applied, and there's no unified way to measure quality across teams. To improve consistency across your AI practices: * You can [launch an AI Governance Scorecard](/guides/ai-excellence/establish-consistent-ai-security-controls#step-1-create-the-scorecard-and-configure-its-basic-settings). Cortex provides an AI Governance template in-app, which can be modified based on your organization's needs. * You can [launch an Initiative](/guides/ai-excellence/establish-consistent-ai-security-controls#create-an-ai-governance-initiative) associated with the Scorecard, which gives your engineers a deadline for when to complete certain goals. * [Use reports and Cortex MCP](/guides/ai-excellence/establish-consistent-ai-security-controls#measuring-success) to better understand progress and next steps. ## Create an AI Governance Scorecard ### Step 1: Create the Scorecard and configure its basic settings 1. On the [**Scorecards** page](https://app.getcortexapp.com/admin/scorecards) in your workspace, click **Create Scorecard**. 2. On the `AI Governance` template, click **Use**. 3. Configure basic settings, including the Scorecard's name, unique identifier, description, and more. * Learn about configuring the basic settings in the [Creating a Scorecard documentation](/standardize/scorecards/create). ### Step 2: Review and modify rules Cortex's templated rules are based on common industry standards: > **AI Governance: Bronze level rules** > > * Secrets scanning and management\\ > > `git.fileExists(".github/workflows/*") AND git.codeSearch(query = "secret", fileExtension = "yml").length > 0` > * PR reviews required from two or more reviewers\\ > > `git.branchProtection().numReviewsRequired > 1` > * AI security documentation and guidelines\\ > > `git.fileExists("AI-SECURITY.md") OR git.fileExists("docs/ai-security.md") OR git.fileExists("docs/AI_USAGE_POLICY.md") OR git.fileExists("RESPONSIBLE_AI.md")` > * Dependency vulnerability scanning\\ > > `git.fileExists(".github/workflows/*") AND (git.codeSearch(query = "dependabot", fileExtension = "yml").length > 0 OR git.codeSearch(query = "safety", fileExtension = "yml").length > 0 OR git.codeSearch(query = "snyk", fileExtension = "yml").length > 0)` > * PR reviews from CODEOWNERS\\ > > `git.branchProtection().codeOwnerReviewsRequired == "true"` > * AI service configuration security\\ > > `git.fileExists("AI-SERVICE-CONFIGURATION-POLICY.md")` > **AI Governance: Silver level rules** > > * Mitre ATLAS matrix\\ > > `custom("owners-reviewed-mitre-atlas-matrix") == "true"` > * Monitoring and alerting for AI applications\\ > > `datadog.monitors().filter((monitor) => monitor.name.matches(".*ai.*|.*model.*|.*ml.*")).length > 0` > * Automated security testing in CI/CD\\ > > `git.fileExists(".github/workflows/*") AND (git.codeSearch(query = "security", fileExtension = "yml").length > 0 OR git.codeSearch(query = "sast", fileExtension = "yml").length > 0 OR git.codeSearch(query = "container.*scan", fileExtension = "yml").length > 0)` > * Data privacy and PII protection measures\\ > > `git.fileExists("PRIVACY.md") OR git.fileExists("DATA-HANDLING.md") OR git.fileExists("docs/privacy.md") OR git.codeSearch(query = "PII", fileExtension = "md").length > 0` > * AI model access controls and authentication\\ > > `git.fileExists("AI-MODEL-ACCESS-CONTROLS.md")` > * External AI vendor risk assessment\\ > > `git.fileExists("AI-VENDORS.md") OR git.fileExists("APPROVED-AI-SERVICES.md") OR git.fileExists("docs/ai-vendor-security.md")` > **AI Governance: Gold level rules** > > * Incident response plan for AI security\\ > > `git.fileExists("AI-INCIDENT-RESPONSE.md") OR git.fileExists("docs/ai-incidents.md") OR git.codeSearch(query = "ai.*incident|model.*breach", fileExtension = "md").length > 0` > * Standford NLP version\\ > > `packageVersion("stanfordnlp") >= semver("4.5.10")` > * AI ethics and bias testing framework\\ > > `git.fileExists("ETHICS.md") OR git.fileExists("BIAS-TESTING.md")` > * AI security training and awareness documentation\\ > > `git.fileExists("AI-TRAINING.md") OR git.fileExists("docs/ai-security-training.md") OR git.codeSearch(query = "training|awareness|security.*guideline", fileExtension = "md").length > 0` > * No secret scanning vulnerabilities\\ > > `git.numOfVulnerabilities(source=["GITHUB_SECRET_SCANNING"]) == 0` > * Adversarial attack detection and prevention\\ > > `git.fileExists("ADVERSARIAL-TESTING.md") OR git.codeSearch(query = "tests/*adverserial*").length > 0` > * No critical vulnerabilities\\ > > `git.numOfVulnerabilities(severity=["CRITICAL"]) == 0` > * AI compliance and regulatory documentation\\ > > `git.fileExists("AI-COMPLIANCE.md") OR git.fileExists("NIST-AI-RMF.md") OR git.fileExists("docs/ai-governance.md") OR git.codeSearch(query = "compliance|regulation|gdpr|nist", fileExtension = "md").length > 0` > * Open NLP version\\ > > `packageVersion("opennlp") >= semver("2.5.5")` You can reorder, delete, and edit rules, add more rules to a level, and assign more points to a rule to signify its importance. Behind each rule is a [Cortex Query Language (CQL) ](/standardize/cql)query; you can edit the existing CQL or write your own queries to further refine your rules. ## Create an AI Governance Initiative Follow the steps below to create an Initiative: > **Create an AI Governance Initiative** > > To motivate change by a certain deadline, you can create an Initiative: > > 1. While viewing your AI Governance Scorecard, click **Create Initiative** in the upper right. > 2. Configure the Initiative fields, including a descriptive name so your team members understand the purpose of the Initiative. For example, `Complete Bronze level AI Governance rules by end of quarter`. > * Make sure to enable notifications so users are notified if an entity they own is failing the Initiative's goal. > 3. Save the Initiative. > > After the Initiative is published, entity owners will be notified if their entity is not meeting the goal. > > Learn more about [creating Initiatives in the docs](/improve/initiatives). ## Measuring success To understand progress of your Scorecard: * Ask [Cortex MCP,](/get-started/cortex-ai-assistant/mcp) "How is my AI Governance Scorecard doing?" The MCP will respond with information on the entities that are failing rules and suggested next steps. * Review reports: The [Bird's Eye report](/improve/reports/birds-eye) gives insight into how entities are performing against the Scorecard by visualizing the data as a heat map:\ ![The AI Governance Scorecard in the Bird's Eye report shows mostly passing entities and only two that are failing a rule.](https://mintcdn.com/cortex-290c0c42/qRY2zZcIyXqFVeCq/guides/images/ai-gov-birdseye.jpg?fit=max\&auto=format\&n=qRY2zZcIyXqFVeCq\&q=85\&s=2eaf9d4719917956b61191b825e3baa0) You can also review your Engineering Intelligence metrics for impact on key engineering metrics, such as: * **MTTR**: With best practices in place, such as incident response plans and AI security runbooks linked, you should see faster incident response. * **Incident frequency**: You may see less incidents overall with the implementation of rules such as requiring more than one PR review and proactively ensuring there are no critical vulnerabilities. # Measure AI impact Source: https://docs.cortex.io/guides/ai-excellence/measure-ai-impact You can leverage the [Eng Intelligence](/improve/eng-intelligence) features in Cortex to measure the impact of AI. ### Copilot Dashboard The [Copilot Dashboard](/improve/eng-intelligence/dashboards/ai-impact) provides insights into the adoption and impact of AI coding tools (starting with GitHub Copilot) across your engineering teams. It allows you to: * **View AI adoption rates by team:** See how many developers are actively using Copilot and how adoption trends over time. * **Correlate AI usage with engineering performance:** Compare key metrics (cycle time, deployment frequency, incident frequency, merged PRs, PR size, time to resolution, and work items completed) between teams or users who use AI tools and those who do not. * **Track AI adoption over time:** Monitor how Copilot usage changes and how it affects delivery and reliability metrics. * **Filter and analyze:** Use filters for time range, team, user, and more to drill into the data that matters most to you. These insights help you identify whether AI tools are improving efficiency, accelerating delivery, or introducing new risks, and allow you to take targeted action based on real data. ### Data Explorer [Data Explorer](/improve/eng-intelligence/data-explorer) includes AI-specific metrics such as: * **AI adoption rate:** Percentage of licensed seats that are active users of AI coding tools. * **Active AI users:** Number of users who used AI tools in a given period. You can group any Eng Intelligence metric by the Cortex-generated "AI Usage" user label to compare performance between AI users and non-AI users. ## Drive continuous Improvement You can use insights from the Copilot Dashboard and Data Explorer to understand what your teams are doing well and areas where they could improve. Use this data to inform your next steps and promote continuous improvement. For example, if you notice a spike in incidents among AI users, you could [create an Initiative](/improve/initiatives) to improve test coverage or code review practices. # Prepare for effective use of AI tools Source: https://docs.cortex.io/guides/ai-excellence/prepare-for-effective-use-of-ai-tools To prepare your services for effective usage of AI tools, you can use the AI Maturity Scorecard template. This Scorecard validates the presence of essential files, pre-commit, safeguards, and observability integrations, ensuring you can effectively leverage AI tools across the software lifecycle. ## Create a Scorecard for AI Maturity ### Step 1: Create the Scorecard and configure its basic settings 1. On the [**Scorecards** page](https://app.getcortexapp.com/admin/scorecards) in your workspace, click **Create Scorecard**. 2. On the `AI Maturity` template, click **Use**. 3. Configure basic settings, including the Scorecard's name, unique identifier, description, and more. * Learn about configuring the basic settings in the [Creating a Scorecard documentation](/standardize/scorecards/create). ### Step 2: Review and modify rules Cortex's templated rules are based on common industry standards: > **AI Maturity: Bronze level rules** > > * Git PR templates exist\\ > > `git.fileExists("pull_request_template.md") OR git.fileExists("docs/pull_request_template.md") OR git.fileExists(".github/PULL_REQUEST_TEMPLATE.md") OR git.fileExists(".github/pull_request_template.md") OR git.fileExists(".github/PULL_REQUEST_TEMPLATE/*.md") OR git.fileExists("PULL_REQUEST_TEMPLATE/*.md") OR git.fileExists("docs/PULL_REQUEST_TEMPLATE/*.md")` > * Pre-commit settings file\\ > > `git.fileExists(".pre-commit-config.yaml")` > * Repository contains README file\\ > > `git.fileExists("README.md")` > **AI Maturity: Silver level rules** > > * Anthropic Claude instructions in repo\\ > > `git.fileExists("CLAUDE.md")` > * Google Gemini instructions in repo\\ > > `git.fileExists("GEMINI.md")` > * GitHub Copilot coding agent development environment\\ > > `git.fileExists(".github/workflows/copilot-setup-steps.yml")` > * GitHub Copilot instructions in repo\\ > > `git.fileExists(".github/copilot-instructions.md")` > * Amazon Q instructions in repo\\ > > `git.fileExists("AmazonQ.md")` > **AI Maturity: Gold level rules** > > * Amazon Q rules in repo\\ > > `git.fileExists(".amazonq/rules/*.md")` > * GitHub Copilot rules in repo\\ > > `git.fileExists(".github/instructions/*.instructions.md")` > * Cursor rules in repo\\ > > `git.fileExists(".cursor/rules/*")` > * AI-driven anomaly detection in observability stack\\ > > `datadog.monitors().filter((monitor) => monitor.name.matches(".ai.")).length > 0` You can reorder, delete, and edit rules, add more rules to a level, and assign more points to a rule to signify its importance. Behind each rule is a [Cortex Query Language (CQL) ](/standardize/cql)query; you can edit the existing CQL or write your own queries to further refine your rules. # Scaffold an ML model project Source: https://docs.cortex.io/guides/ai-excellence/scaffold-ml-model You can use a Workflow in Cortex to scaffold new Machine Learning (ML) projects with best practices built in from the start. ### Step 1: Create an entity type called ML Model In Cortex, [create a custom entity type](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/entity-types#creating-a-custom-entity-type) called ML Model (with a unique entity type identifier `ml-model`). ### Step 2: Register the cookiecutter template in Cortex Follow the [Cortex documentation on registering a Scaffolder template](/streamline/workflows/scaffolder), > **Add the template** > > You must have the `Configure Scaffolder templates` permission to follow these steps. > > 1. In Cortex, navigate to **Workflows** from the main nav. In the upper right corner of the page, click **Register Scaffolder template**. > > ![In the upper right corner click 'Register Scaffolder template.'](https://mintcdn.com/cortex-290c0c42/qRY2zZcIyXqFVeCq/guides/images/register-scaffolder-template.jpg?fit=max\&auto=format\&n=qRY2zZcIyXqFVeCq\&q=85\&s=281f96c56af7d87729dfabaf65013a71) > > 2. Configure the template details: > * **Provider**: Select which Git provider you are using. > * **Name**: Enter a name for the template, such as "MLOps cookiecutter" > * **Description**: Add a description, such as "A standardized, flexible project structure for MLOps" > * **Tags**: Optionally, add tags to describe the template. We recommend adding a tag such as "mlops". > 3. Under "Configuration," fill in the fields: > * **Git provider configuration**: Enter the configuration, e.g., `default` > * By default, the option **Use this configuration for all git operations** is **enabled**. When enabled, Cortex uses the selected configuration for **all** Git operations (e.g., fetching the template details, populating the form options, and creating the new repo or Pull Request). The form options will be filtered to only those organizations or repositories that the selected configuration has access to. > * With this setting **disabled**, you can use a single Scaffolder template with multiple organizations/configurations. While the selected configuration must still have to access the template's repository, the remaining Git operations will be run dynamically based on the user's form selections. The Scaffolder form options will be populated using data from all configurations. Then, Cortex will automatically use a configuration with access to the selected organization (if scaffolding a new repository) or repository (if scaffolding a new PR) for all remaining Git operations. > * **Git URL**: Enter the git URL where your template lives. > * In this example we are using the [MLOps cookiecutter template in Cortex's Solutions repository](https://github.com/cortexapps/solutions/tree/master/workflows/scaffolders/cookiecutter-mlops): `https://github.com/cortexapps/solutions/tree/master/workflows/scaffolders/cookiecutter-mlops` > * **Configuration requirements**: Select `Neither`, as this Scaffolder will create entities for the `ml-model` type rather than creating entities of the `service` type. > * **Visibility**: When creating a new repository choose the default visibility of the repository. If you do not specify, the template defaults to setting a new repository as private. > * The available options depend on the Git provider. The `Public` setting only works if the org containing the repository allows it. The `Internal` setting only works for GitHub Enterprise accounts. > * When running a Workflow that contains a Scaffolder block, you can configure an override to change the repo visibility. > * **Create cortex.yaml in git when creating a new service**: Disable this setting, as the Workflow you run will include a block to add the new entity to your workspace. > * **Show README.md during Scaffolding**: When enabled, the project's README.md will be displayed when inputting the variables to use while rendering the template. If there is no README.md, nothing will be shown. > 4. Click **Register Scaffolder template**. ### Step 3: Create a Workflow with a Scaffolder block You can use the [Cortex CLI](https://pypi.org/project/cortexapps-cli/) to add the example Workflow to your workspace. This allows you to quickly set up the example configuration then iterate on it for your own use case. Expand the tile below to learn more: > **Import the Workflow via CLI** > > 1. Save the Workflow example YAML file below: > > ```yaml theme={null} > name: New ML Model > tag: scaffolder-workflow-a1d4d2d3-624c-473f-a9f2-b933a44a92df > description: "Workflow that leverages the [cookiecutter-mlops](https://github.com/Chim-SO/cookiecutter-mlops)\ > \ template to create new logical, reasonably standardized, but flexible project\ > \ structure for MLOps." > isDraft: true > filter: > type: GLOBAL > runResponseTemplate: "Your repository is ready! \nPlease browse to {{actions.create-repo.outputs.response.gitURL}}\n\ > The Model is also being tracked in Cortex. Please browse to https://app.getcortexapp.com/admin/index?tag={{actions.slugify-project-name.outputs.result}}" > failedRunResponseTemplate: null > restrictActionCompletionToRunnerUser: false > actions: > - name: Gathering Model Details... > slug: model-details > schema: > inputs: > - name: Project Name > description: null > key: project-name > required: false > defaultValue: null > placeholder: null > validationRegex: null > type: INPUT_FIELD > - name: Description > description: null > key: description > required: false > defaultValue: null > placeholder: null > validationRegex: null > type: TEXTAREA_FIELD > - name: License > description: null > key: license > required: false > options: > - MIT > - BSD-3-Clause > - No license file > optionsLabels: > - MIT > - BSD-3-Clause > - No license file > defaultValue: null > placeholder: null > allowAdditionalOptions: false > type: SELECT_FIELD > - name: s3 Bucket > description: null > key: s3-bucket > required: false > defaultValue: null > placeholder: "[Optional] do not include 's3://'" > validationRegex: null > type: INPUT_FIELD > - name: AWS Profile > description: null > key: aws-profile > required: false > defaultValue: default > placeholder: default > validationRegex: null > type: INPUT_FIELD > - name: Python Interpreter > description: null > key: python-interpreter > required: false > options: > - Python > - Python3 > optionsLabels: > - Python > - python3 > defaultValue: null > placeholder: null > allowAdditionalOptions: false > type: SELECT_FIELD > inputOverrides: [] > jsValidatorScript: "" > type: USER_INPUT > outgoingActions: > - slugify-project-name > isRootAction: true > - name: Getting Ready to Scaffold New Repository... > slug: slugify-project-name > schema: > expression: .actions."model-details".outputs."project-name" | ascii_downcase | > gsub(" ";"-")|gsub("_";"-") > type: JQ > outgoingActions: > - create-repo > isRootAction: false > - name: Creating Repository in GitHub... > slug: create-repo > schema: > scaffolderTemplateId: st38e74ce20dc23c29 > createNewRepository: true > createService: false > inputOverrides: > - inputKey: project_name > outputVariable: actions.model-details.outputs.project-name > editable: false > type: VALUE > - inputKey: author_name > outputVariable: context.initiatedBy.email > editable: false > type: VALUE > - inputKey: description > outputVariable: actions.model-details.outputs.description > editable: false > type: VALUE > - inputKey: repo_name > outputVariable: actions.slugify-project-name.outputs.result > editable: false > type: VALUE > - inputKey: open_source_license > outputVariable: actions.model-details.outputs.license > editable: false > type: VALUE > - inputKey: s3_bucket > outputVariable: actions.model-details.outputs.s3-bucket > editable: false > type: VALUE > - inputKey: aws_profile > outputVariable: actions.model-details.outputs.aws-profile > editable: false > type: VALUE > - inputKey: python_interpreter > outputVariable: actions.model-details.outputs.python-interpreter > editable: false > type: VALUE > - inputKey: publisherOrg > outputVariable: variables.org > editable: false > type: VALUE > - inputKey: publisherRepoName > outputVariable: actions.slugify-project-name.outputs.result > editable: false > type: VALUE > - inputKey: publisherBranch > outputVariable: variables.branch-name > editable: false > type: VALUE > - inputKey: publisherCommitMessage > outputVariable: variables.commit-msg > editable: false > type: VALUE > - inputKey: publisherRepoVisibility > outputVariable: variables.visibility > editable: false > type: VALUE > type: SCAFFOLDER > outgoingActions: > - add-entity-to-catalog > isRootAction: false > - name: Adding Entity to Catalog... > slug: add-entity-to-catalog > schema: > inputs: > body: "openapi: 3.0.1\ninfo:\n title: {{actions.model-details.outputs.project-name}}\n\ > \ x-cortex-tag: {{actions.slugify-project-name.outputs.result}}\n x-cortex-type:\ > \ ml-model\n x-cortex-git:\n github:\n repository: {{variables.org}}/{{actions.slugify-project-name.outputs.result}}\n\ > \ x-cortex-groups:\n - ml-model \n " > dryRun: false > appendArrays: false > failIfEntityDoesNotExist: false > integrationAlias: null > actionIdentifier: cortex.createOrPatchEntity > type: ADVANCED_HTTP_REQUEST > outgoingActions: > - notify-end-user > isRootAction: false > - name: Notifying User... > slug: notify-end-user > schema: > channel: demos > message: "Your repository is ready! \nPlease browse to {{actions.create-repo.outputs.response.gitURL}}\n\ > The Model is also being tracked in Cortex. Please browse to https://app.getcortexapp.com/admin/index?tag={{actions.slugify-project-name.outputs.result}}" > type: SLACK > outgoingActions: [] > isRootAction: false > runRestrictionPolicies: [] > iconTag: null > variables: > - slug: commit-msg > type: STRING > defaultValue: Initial Commit > - slug: branch-name > type: STRING > defaultValue: main > - slug: visibility > type: STRING > defaultValue: PUBLIC > - slug: org > type: STRING > defaultValue: > > ``` > > 2. Use the [Cortex CLI](https://pypi.org/project/cortexapps-cli/) to run this command, using the path to your Workflow YAML file: `cortex workflows create -f ` ### Step 4: Run the Workflow While viewing the Workflow in Cortex, click **Run**. When you run the Workflow, the following events happen: * The User Input block runs, collecting input from the user running the Workflow * A new ML project is scaffolded in your Git repository, using the information collected from the initial User Input block * A corresponding new entity (of the type `ml-model`) is created in your workspace * A notification is sent to the Slack channel you configured in the Slack block of the Workflow # Set benchmarks for AI readiness Source: https://docs.cortex.io/guides/ai-excellence/set-benchmarks-for-ai-readiness You can use Cortex's AI Readiness Scorecard template to start setting benchmarks and checking whether your services meet criteria for your goals. The AI Readiness template evaluates whether services have the foundational software engineering practices in place to safely and effectively adopt AI technologies. ## Create a Scorecard for AI Readiness ### Step 1: Create the Scorecard and configure its basic settings 1. On the [**Scorecards** page](https://app.getcortexapp.com/admin/scorecards) in your workspace, click **Create Scorecard**. 2. On the `AI Readiness` template, click **Use**. 3. Configure basic settings, including the Scorecard's name, unique identifier, description, and more. * Learn about configuring the basic settings in the [Creating a Scorecard documentation](/standardize/scorecards/create). ### Step 2: Review and modify rules Cortex's templated rules are based on common industry standards: > **AI Readiness: Bronze level rules** > > * Version control in use\\ > > `git != null` > * Basic documentation exists\\ > > `git.fileExists("README.md") OR git.fileExists("docs/README.md") OR git.fileExists("API.md")` > * Service ownership defined\\ > > `ownership.allOwners().length > 0` > * Basic health monitoring\\ > > `datadog.monitors().length > 0` > * Dependency management\\ > > `dependencies.in().length > 0 or dependencies.out().length > 0` > **AI Readiness: Silver level rules** > > * Automated CI/CD pipeline\\ > > `git.fileExists(".github/workflows/*.yml") OR git.fileExists("Jenkinsfile") OR git.fileExists(".gitlab-ci.yml") OR git.fileExists("azure-pipelines.yml")` > * Integration testing implemented > * `git.codeSearch(query = "integration.*test|test.*integration", fileExtension = "*").length > 0 OR captures("integration-tests", custom("integration_tests_exist")) == "enabled"` > * SLO defined\\ > > `slos().length > 0` > * Test coverage minimum met\\ > > `captures("test-coverage", sonarqube.metric("coverage") >= 80)` > * Secret management implemented\\ > > `git.fileExists(".github/workflows/*") AND git.codeSearch(query = "secret", fileExtension = "yml").length > 0` > * Incident response runbook\\ > > `links("RUNBOOK").length > 0` > * Deployment rollback capability\\ > > `captures("rollback", custom("rollback_capability")) == "enabled" OR git.codeSearch(query = "rollback|revert|previous.*version", fileExtension = "*").length > 0` > **AI Readiness: Gold level rules** > > * Distributed tracing implemented\\ > > `captures("tracing", custom("distributed_tracing")) == "enabled" OR git.codeSearch(query = "jaeger|zipkin|opentelemetry|tracing", fileExtension = "*").length > 0` > * Change approval process\\ > > `links("CHANGE_APPROVAL").length > 0` > * Data classification documented\\ > > `git.fileExists("DATA-CLASSIFICATION.md") OR git.codeSearch(query = "data.*classif|pii|sensitive.*data|gdpr", fileExtension = "md").length > 0` > * Comprehensive audit logging\\ > > `captures("audit-log", custom("audit_logging")) == "enabled" OR git.codeSearch(query = "audit.*log|compliance.*log|access.*log", fileExtension = "*").length > 0` > * Feature flags for controlled rollouts\\ > > `launchDarkly != null` > * Zero critical and high vulnerabilities\\ > > `captures("critical-vulns", custom("critical_vulnerabilities")) == 0 AND captures("high-vulns", custom("high_vulnerabilities")) == 0` > * AI model security scanning\\ > > `captures("model-scan", custom("ai_model_scanning")) == "enabled" OR git.codeSearch(query = "model.*scan|adversarial.*test|bias.*detect", fileExtension = "*").length > 0` You can reorder, delete, and edit rules, add more rules to a level, and assign more points to a rule to signify its importance. Behind each rule is a [Cortex Query Language (CQL) ](/standardize/cql)query; you can edit the existing CQL or write your own queries to further refine your rules. # Verify services after AI-based auto-mapping Source: https://docs.cortex.io/guides/ai-excellence/verify-auto-mappings While importing your data, [Cortex automatically recommends team owners](/ingesting-data-into-cortex/entities-overview/entities/ownership/viewing-and-managing-ownership#finding-entities-without-owners) for entities that do not have an owner. A user with the `Edit entities` permission can accept these recommendations in bulk. When making changes in bulk, it is best practice to ensure the data is verified soon after. [Data verifications](/configure/settings/entity-settings/verification) ensure that entity data in the catalog (e.g., ownership and metadata) stays accurate over time. ### Set up a data verification for your recently imported entities If you have not reviewed each entity's recommended owner individually, you can set up a data verification to make sure owners review and verify the data within a specified timeframe. You must have the `Configure verification periods` permission to set up a verification. 1. In Cortex, navigate to the [Entity verification settings](https://app.getcortexapp.com/admin/settings/entities/verification) page. Click **+Add verification period**. 2. In the side panel, fill in the fields: * **Start date** and **End date**: Enter the start and end dates for the verification period. * The start date cannot be in the past. The end date must be at least one day after the start date. * Choose a timeframe that is reasonable based on the number of entities that each team will need to verify. * **Name**: Enter a descriptive name, e.g., `Verify auto-mapped entities`. * **Verification instructions**: Enter clear and concise instructions that will appear on the entity's details page, e.g., `These entity owners were mapped via AI-based recommendations. Please review and verify the entity's ownership and metadata.` * **Require reason for verification**: Check this box to require the user to include a reason if they confirm that the entity's data is invalid. * We recommend requiring a reason, as it will allow you to quickly understand what needs to be fixed on an entity. * **Team member roles responsible for verification**: Select which Cortex users will be responsible for verifying data. * If you select multiple roles, any of those users can verify data. * If you do not select a team member role, any user who owns the entity can verify data. * **Entities to verify**: Specify which entities the verification policy applies to. * You can select a specific entity type to include (for example, you could apply the verification to all entities of the type `service`) or if your entities have groups assigned, you can filter by specific groups. * Under **Advanced options**, you can use CQL to refine which entities you want to verify. For example, you might narrow your selection to entities created in the last two weeks:\ `entity.created() < duration("P2W")` 3. Click **Create verification period**. Within a few minutes of saving the verification period, it will be visible to admins in the list of verifications on the [Entity verification settings page](https://app.getcortexapp.com/admin/settings/entities/verification). ## Remediate entities with incorrect data After setting up the verification period, you can [create a CQL report to view all entities that have been verified as incorrect](/configure/settings/entity-settings/viewing-and-verifying-data-verifications#viewing-verification-statuses) using a prebuilt CQL report template. Cortex also offers a prebuilt [Scorecard template to flag entities that have not yet been verified](/configure/settings/entity-settings/viewing-and-verifying-data-verifications#flagging-unverified-entities-via-a-scorecard). # Bulk accept entity data verifications Source: https://docs.cortex.io/guides/compliance/bulk-accept-entity-data-verifications Let owners accept verification for all of their entities in one run, instead of one entity at a time This guide explains how to use a Workflow to let entity owners accept verification for many entities at once during a [verification period](/configure/settings/entity-settings/verification). By default, owners verify entities one at a time from each entity's page. With this Workflow, an owner picks an open verification period, selects the entities they own, and marks all of them as verified correct in a single run. > [!TIP] > > Link to this Workflow in your verification period's **Verification instructions**, for example: *"To bulk accept the entities you own, run the Bulk Entity Verification workflow: \[link]"*. Owners can then choose to verify one entity from its entity page, or open the Workflow to accept several at once. ## Create a Workflow to bulk accept entity verifications ### Prerequisites Before getting started: * You must have the `Edit Workflows` [permission](/configure/settings/managing-users/permissioning) to create the Workflow, and the `Execute Workflow runs` permission to run it. * To verify entities, at least one verification period must be open. If none are open, the run ends with a "No open verification periods found" message and nothing is verified. * The person running the Workflow must own the entities they verify, and hold any roles the verification period requires. ### Step 1: Create the Workflow You can create a Workflow in the Cortex UI or via the Cortex CLI. **Cortex CLI** #### Add the Workflow via CLI You can use the [Cortex CLI](https://pypi.org/project/cortexapps-cli/) to add the example Workflow to your workspace. This allows you to quickly set up the example configuration then iterate on it for your own use case. Expand the tile below to learn more: > **Import the Workflow via CLI** > > 1. Save the Workflow example YAML file below: > > ```yaml theme={null} theme={null} > name: Bulk Entity Verification > tag: bulk-entity-verification > description: Select entities you own and mark them all as verified correct for an open verification period in one step. > isDraft: true > isRunnableViaApi: false > restrictActionCompletionToRunnerUser: true > iconTag: CheckCircle > filter: > type: GLOBAL > runRestrictionPolicies: [] > variables: > - slug: result-message > type: STRING > defaultValue: "" > description: Summary shown as the run response; set by whichever path the run takes. > runResponseTemplate: "{{variables.result-message}}" > failedRunResponseTemplate: Bulk verification failed. Check the failed step's output for details. > actions: > - name: Fetch open verification periods > slug: fetch-periods > isRootAction: true > outgoingActions: > - format-periods > schema: > type: HTTP_REQUEST > httpMethod: GET > url: /api/v1/verification-periods?isActive=true&pageSize=250&page=0 > integration: Cortex > headers: > Accept: application/json > > - name: Format periods for dropdown > slug: format-periods > isRootAction: false > outgoingActions: > - check-periods > schema: > type: JQ > expression: >- > .actions["fetch-periods"].outputs.body > | (if type == "string" then fromjson else . end) > | (.periods // []) > | map("\(.name) (\(.cid))") > > - name: Any open periods? > slug: check-periods > isRootAction: false > outgoingActions: > - select-entities > - no-periods-message > schema: > type: CONDITIONAL_BRANCH > branches: > - type: CONDITIONAL > slug: has-open-periods > name: Open periods found > expression: size(actions["format-periods"].outputs.result) > 0 > outgoingAction: select-entities > fallbackBranch: > type: FALLBACK > slug: no-open-periods > name: No open periods > outgoingAction: no-periods-message > > - name: Set 'no periods found' message > slug: no-periods-message > isRootAction: false > outgoingActions: [] > schema: > type: SET_VARIABLES > variables: > - slug: result-message > source: > type: JAVASCRIPT > script: >- > return "No open verification periods found. Nothing was verified. > Ask an admin to open a verification period, then run this workflow again."; > > - name: Select entities to verify > slug: select-entities > isRootAction: false > outgoingActions: > - build-payload > schema: > type: USER_INPUT > jsValidatorScript: "" > inputOverrides: > - type: OPTION > inputKey: period > outputVariable: actions.format-periods.outputs.result > inputs: > - type: SELECT_FIELD > key: period > name: Verification period > description: Open verification periods in this workspace. > required: true > allowAdditionalOptions: false > options: [] > - type: CORTEX_ENTITY_FIELD > key: entities > name: Entities to verify > description: Choose the entities you own that you confirm are correct. Only entities you own are listed. > required: true > allowMultiple: true > limitEntitiesToRunnerUserScope: true > shouldDisplayOptionsAsHierarchy: false > entityFilter: {} > - type: TOGGLE_FIELD > key: confirm > name: I confirm these entities' details are correct > required: true > defaultValue: false > > - name: Build verification payload > slug: build-payload > isRootAction: false > outgoingActions: > - bulk-verify > schema: > type: JQ > expression: |- > .actions["select-entities"].outputs as $in > | if ($in.confirm != true) then > error("Confirmation toggle was not turned on; nothing was verified.") > else > ($in.period | capture("\\((?vp[0-9a-zA-Z]+)\\)$").cid) as $period > | ($in.entities > | if type == "array" then . else [.] end > | map(if type == "object" then (.tag // .cid) else . end)) as $tags > | { > count: ($tags | length), > periodCid: $period, > body: ({verifications: [$tags[] | {entity: ., periodCid: $period, status: "VERIFIED_CORRECT"}]} | tojson) > } > end > > - name: Bulk verify > slug: bulk-verify > isRootAction: false > outgoingActions: > - result-summary > schema: > type: HTTP_REQUEST > httpMethod: PUT > url: /api/v1/verifications > integration: Cortex > headers: > Content-Type: application/json > payload: "{{{actions.build-payload.outputs.result.body}}}" > > - name: Set result summary > slug: result-summary > isRootAction: false > outgoingActions: [] > schema: > type: SET_VARIABLES > variables: > - slug: result-message > source: > type: JAVASCRIPT > script: |- > const raw = actions["bulk-verify"].outputs.body; > let body = raw || {}; > if (typeof raw === "string") { try { body = JSON.parse(raw); } catch (e) { body = { raw: raw }; } } > const sent = actions["build-payload"].outputs.result.count; > const period = actions["select-entities"].outputs.period; > const errors = Array.isArray(body.errors) ? body.errors : []; > const noun = (n) => n === 1 ? "entity" : "entities"; > if (errors.length === 0) { > return `Verified ${sent} ${noun(sent)} as correct for ${period}.`; > } > const ok = Math.max(sent - errors.length, 0); > return `Submitted ${sent} ${noun(sent)} for ${period}: ${ok} verified, ${errors.length} failed.\n` + errors.map(e => "- " + (typeof e === "string" ? e : JSON.stringify(e))).join("\n"); > ``` > > 2. Use the [Cortex CLI](https://pypi.org/project/cortexapps-cli/) to run this command, using the path to your Workflow YAML file: `cortex workflows create -f ` **Cortex UI** #### Step 1.1: Create the Workflow and configure basic settings 1. In Cortex, navigate to **Workflows**. In the upper right corner, click **+Create workflow**. Choose a blank Workflow. 2. Follow the documentation to [configure the basic settings for your Workflow](/streamline/workflows/create#creating-a-workflow). * In this example, we use the name `Bulk Entity Verification`. * Leave the scope set to **Global**, so the Workflow isn't tied to a single entity. 3. In the Workflow settings, add a variable: * **Slug**: `result-message` * **Type**: String 4. Set the **Run response template** to `{{variables.result-message}}`. #### Step 1.2: Add blocks to the Workflow Add the following blocks to your Workflow: > **Fetch open verification periods** > > This block gets the verification periods that are open today. > > 1. Click **+** in the center of the page. In the block library modal, choose **HTTP request**. > 2. In the block configuration side panel, enter a name and unique slug for this block. > * In this example, we use the name `Fetch open verification periods` and the slug `fetch-periods`. > 3. Configure the block: > * **HTTP method**: GET > * **Integration**: Cortex > * **URL**: `/api/v1/verification-periods?isActive=true&pageSize=250&page=0` > * **Headers**: `Accept: application/json` > 4. At the bottom of the side panel, click **Save**. > **Format periods for dropdown** > > This block turns each open period into a dropdown option such as `Q4 ownership review (vp0a1b2c3d4e5f6789)`, so users see the period name and the Workflow keeps its ID. > > 1. Click **+** below the previous block. In the block library modal, choose **JQ**. > 2. In the side panel, enter a name and unique slug for the block. > * In this example, we use the name `Format periods for dropdown` and the slug `format-periods`. > 3. Enter the following JQ expression: > > ```jq theme={null} theme={null} > .actions["fetch-periods"].outputs.body > | (if type == "string" then fromjson else . end) > | (.periods // []) > | map("\(.name) (\(.cid))") > ``` > > 4. At the bottom of the side panel, click **Save**. > **Any open periods?** > > This block stops the run with a clear message when no verification period is open. > > 1. Click **+** below the previous block. In the block library modal, choose **Branch**. > 2. In the side panel, enter a name and unique slug for the block. > * In this example, we use the name `Any open periods?` and the slug `check-periods`. > 3. Add a conditional branch: > * **Name**: Open periods found > * **Slug**: `has-open-periods` > * **Expression**: `size(actions["format-periods"].outputs.result) > 0` > 4. Name the fallback branch `No open periods`, with the slug `no-open-periods`. > 5. At the bottom of the side panel, click **Save**. > **Set 'no periods found' message** > > On the **No open periods** branch, this block sets the message the user sees. > > 1. On the **No open periods** branch, click **+**. In the block library modal, choose **Set variables**. > 2. In the side panel, enter a name and unique slug for the block. > * In this example, we use the name `Set 'no periods found' message` and the slug `no-periods-message`. > 3. Set the `result-message` variable using JavaScript: > > ```javascript theme={null} theme={null} > return "No open verification periods found. Nothing was verified. Ask an admin to open a verification period, then run this workflow again."; > ``` > > 4. At the bottom of the side panel, click **Save**. > **Select entities to verify** > > On the **Open periods found** branch, this block collects the period, the entities, and a confirmation from the user. > > 1. On the **Open periods found** branch, click **+**. In the block library modal, choose **User input**. > 2. In the side panel, enter a name and unique slug for the block. > * In this example, we use the name `Select entities to verify` and the slug `select-entities`. > 3. Click **+Add user input**. Add the following: > * **Name**: Verification period > * **Key**: period > * **Type**: Select > * **Path to override value**: `actions.format-periods.outputs.result` > * Click **Add input**. > 4. Click **+Add user input**. Add the following: > * **Name**: Entities to verify > * **Key**: entities > * **Type**: Select > * **Data source**: Cortex entity > * Enable **Allow multiple**, and limit the options to entities the runner owns. > * Click **Add input**. > 5. Click **+Add user input**. Add the following: > * **Name**: I confirm these entities' details are correct > * **Key**: confirm > * **Type**: Toggle > * Click **Add input**. > 6. At the bottom of the side panel, click **Save**. > **Build verification payload** > > This block checks that the user turned on the confirmation toggle, reads the period ID from the selected option, and builds one request body for all of the selected entities. > > 1. Click **+** below the previous block. In the block library modal, choose **JQ**. > 2. In the side panel, enter a name and unique slug for the block. > * In this example, we use the name `Build verification payload` and the slug `build-payload`. > 3. Enter the following JQ expression: > > ```jq theme={null} theme={null} > .actions["select-entities"].outputs as $in > | if ($in.confirm != true) then > error("Confirmation toggle was not turned on; nothing was verified.") > else > ($in.period | capture("\\((?vp[0-9a-zA-Z]+)\\)$").cid) as $period > | ($in.entities > | if type == "array" then . else [.] end > | map(if type == "object" then (.tag // .cid) else . end)) as $tags > | { > count: ($tags | length), > periodCid: $period, > body: ({verifications: [$tags[] | {entity: ., periodCid: $period, status: "VERIFIED_CORRECT"}]} | tojson) > } > end > ``` > > 4. At the bottom of the side panel, click **Save**. > **Bulk verify** > > This block sends every selected entity to the [bulk verification endpoint](/api/rest/verifications#put-api-v1-verifications) in a single request. > > 1. Click **+** below the previous block. In the block library modal, choose **HTTP request**. > 2. In the side panel, enter a name and unique slug for the block. > * In this example, we use the name `Bulk verify` and the slug `bulk-verify`. > 3. Configure the block: > * **HTTP method**: PUT > * **Integration**: Cortex > * **URL**: `/api/v1/verifications` > * **Headers**: `Content-Type: application/json` > * **Payload**: `{{{actions.build-payload.outputs.result.body}}}` > 4. At the bottom of the side panel, click **Save**. > **Set result summary** > > This block sets the message the user sees after the bulk request. It reports how many entities were verified and lists any that failed. > > 1. Click **+** below the previous block. In the block library modal, choose **Set variables**. > 2. In the side panel, enter a name and unique slug for the block. > * In this example, we use the name `Set result summary` and the slug `result-summary`. > 3. Set the `result-message` variable using JavaScript: > > ```javascript theme={null} theme={null} > const raw = actions["bulk-verify"].outputs.body; > let body = raw || {}; > if (typeof raw === "string") { try { body = JSON.parse(raw); } catch (e) { body = { raw: raw }; } } > const sent = actions["build-payload"].outputs.result.count; > const period = actions["select-entities"].outputs.period; > const errors = Array.isArray(body.errors) ? body.errors : []; > const noun = (n) => n === 1 ? "entity" : "entities"; > if (errors.length === 0) { > return `Verified ${sent} ${noun(sent)} as correct for ${period}.`; > } > const ok = Math.max(sent - errors.length, 0); > return `Submitted ${sent} ${noun(sent)} for ${period}: ${ok} verified, ${errors.length} failed.\n` + errors.map(e => "- " + (typeof e === "string" ? e : JSON.stringify(e))).join("\n"); > ``` > > 4. At the bottom of the side panel, click **Save**. ### Step 2: Run the Workflow In the list of Workflows, locate the "Bulk Entity Verification" Workflow and click **Run**. When you run the Workflow, the following events happen: 1. The Workflow retrieves the verification periods that are open today and formats them as dropdown options. 2. If no period is open, the run ends with the message "No open verification periods found." Nothing is verified. 3. If at least one period is open, the Workflow pauses to collect a response from the user during the User input block. The user selects a verification period, selects one or more entities they own, and turns on the confirmation toggle. 4. The JQ block checks the confirmation toggle. If it is off, the run fails and nothing is verified. Otherwise, it builds a single request that marks each selected entity as `VERIFIED_CORRECT` for the selected period. 5. The HTTP request block sends the request to the bulk verification endpoint. 6. The Workflow sets the run response to a summary of the result, such as "Verified 3 entities as correct for Q4 ownership review (vp0a1b2c3d4e5f6789)." > [!NOTE] > > The bulk verification endpoint evaluates each entity separately. It can return `200 OK` even when some entities were not recorded, for example because the user doesn't own them. Those entities appear under `errors` in the response, and the Workflow lists them in the run summary. # Data verifications for audit readiness Source: https://docs.cortex.io/guides/compliance/data-verification [Data verifications](/configure/settings/entity-settings/verification) ensure that entity data in the catalog (e.g., ownership and metadata) stays accurate over time. As a best practice for audit readiness, we recommend scheduling periodic data verification to ensure your entities are up to date. ## Set up a data verification for audit readiness You must have the `Configure verification periods` permission to set up a verification. 1. In Cortex, navigate to the [Entity verification settings](https://app.getcortexapp.com/admin/settings/entities/verification) page. Click **+Add verification period**. 2. In the side panel, fill in the fields: * **Start date** and **End date**: Enter the start and end dates for the verification period. * The start date cannot be in the past. The end date must be at least one day after the start date. * Choose a timeframe based on your audit's point in time. For example, if your SOC 2 period ends on March 31, you may want to ensure all verifications have timestamps within the last 90 days of that period. * **Name**: Enter a descriptive name, e.g., `Audit readiness`. * **Verification instructions**: Enter clear and concise instructions that will appear on the entity's details page, e.g., `These entities are subject to an upcoming audit. Please review to ensure we stay compliant.` * **Require reason for verification**: Check this box to require the user to include a reason if they confirm that the entity's data is invalid. * We recommend requiring a reason, as it will allow you to quickly understand what needs to be fixed on an entity. * **Team member roles responsible for verification**: Select which Cortex users will be responsible for verifying data. * If you select multiple roles, any team member with one of those roles can verify data. * If you do not select a team member role, any direct member of the entity's owning team can verify data. * Before you restrict verification to a role, confirm that your team members have that role assigned in Cortex. See [Who can verify an entity](/configure/settings/entity-settings/verification.md#who-can-verify-an-entity). * **Entities to verify**: Specify which entities the verification policy applies to. * You can select a specific entity type to include (for example, you could apply the verification to all entities of the type `service`) or if your entities have groups assigned, you can filter by specific groups. * Under **Advanced options**, you can use CQL to refine which entities you want to verify. For example, you might narrow your selection to entities created in the last two weeks:\ `entity.created() < duration("P2W")` 3. Click **Create verification period**. Within a few minutes of saving the verification period, it will be visible to admins in the list of verifications on the [Entity verification settings page](https://app.getcortexapp.com/admin/settings/entities/verification). Entity owners will receive notifications to verify their entities. ## Remediate entities with incorrect data After setting up the verification period, you can [create a CQL report to view all entities that have been verified as incorrect](/configure/settings/entity-settings/verification#view-all-unverified-or-incorrect-entities) using a prebuilt CQL report template. Cortex also offers a prebuilt [Scorecard template to flag entities that have not yet been verified](/configure/settings/entity-settings/verification#flag-unverified-entities-via-scorecard). # Link SOC 2 documents to entity Source: https://docs.cortex.io/guides/compliance/link-soc2-docs This guide explains how to use a Workflow to streamline the process of linking SOC 2 documents to an entity. ## Create a Workflow to link SOC 2 documents to an entity ### Prerequisites Before getting started: * You must have the `Edit Workflows` [permission](/configure/settings/managing-users/permissioning) to create the Workflow, and the `Execute Workflow runs` permission to run it. ### Step 1: Create the Workflow You can create a Workflow in the Cortex UI or via the Cortex CLI. **Cortex CLI** #### Add the Workflow via CLI You can use the [Cortex CLI](https://pypi.org/project/cortexapps-cli/) to add the example Workflow to your workspace. This allows you to quickly set up the example configuration then iterate on it for your own use case. Expand the tile below to learn more: > **Import the Workflow via CLI** > > 1. Save the Workflow example YAML file below: > > ```yaml theme={null} > name: Link SOC2 Documents to Entity > tag: link-soc2-documents-to-an-entity > description: null > isDraft: true > filter: > entityFilter: > typeFilter: > types: > - service > entityGroupFilter: null > ownershipScope: ALL > type: ENTITY > runResponseTemplate: null > failedRunResponseTemplate: null > restrictActionCompletionToRunnerUser: false > actions: > - name: User input > slug: user-input > schema: > inputs: > - name: Link Type > description: null > key: link-type > required: false > options: > - pen-test > - data-retention-policy > optionsLabels: > - Pen Test > - Data Retention Policy > defaultValue: null > placeholder: null > allowAdditionalOptions: false > type: SELECT_FIELD > - name: Link URL > description: null > key: link-url > required: false > defaultValue: null > placeholder: null > validationRegex: null > type: INPUT_FIELD > inputOverrides: [] > jsValidatorScript: "" > type: USER_INPUT > outgoingActions: > - retrieve-entity-descriptor > isRootAction: true > - name: Retrieve entity descriptor > slug: retrieve-entity-descriptor > schema: > inputs: > entityId: "{{context.entity.tag}}" > integrationAlias: null > actionIdentifier: cortex.retrieveEntityDescriptor > type: ADVANCED_HTTP_REQUEST > outgoingActions: > - javascript > isRootAction: false > - name: JavaScript > slug: javascript > schema: > script: |+ > const descriptor = actions['retrieve-entity-descriptor']?.outputs?.descriptor; > const linkType = actions['user-input']?.outputs?.['link-type']; > const linkUrl = actions['user-input']?.outputs?.['link-url']; > > if (!descriptor || typeof descriptor !== 'string') { > throw new Error('Descriptor must be a YAML string.'); > } > const rawType = String(linkType || '').trim(); > const rawUrl = String(linkUrl || '').trim(); > if (!rawType || !rawUrl) { > throw new Error('Both link-type and link-url are required.'); > } > > // Normalize input for mapping > const normalize = s => s.toLowerCase().replace(/[_\s-]+/g, ' ').trim(); > const normType = normalize(rawType); > > let finalType, finalName; > if (normType === 'pen test' || normType === 'pentest') { > finalType = 'pen-test'; > finalName = 'Pen Test'; > } else if (normType === 'data retention policy') { > finalType = 'documentation'; > finalName = rawType; // keep exactly what the user selected > } else { > finalType = rawType; > finalName = rawType; > } > > // Parse YAML > let obj; > try { > if (typeof YAML.load === 'function') { > obj = YAML.load(descriptor) || {}; > } else if (typeof YAML.parse === 'function') { > obj = YAML.parse(descriptor) || {}; > } else { > throw new Error('YAML parser not available in this runtime.'); > } > } catch (err) { > throw new Error('Failed to parse descriptor YAML: ' + err.message); > } > > // Ensure x-cortex-link exists > if (!obj.info) obj.info = {}; > const linkKey = 'x-cortex-link'; > const existing = obj.info[linkKey]; > obj.info[linkKey] = Array.isArray(existing) ? existing : (existing ? [existing] : []); > > // Normalize existing links > const current = obj.info[linkKey] > .filter(Boolean) > .map(l => ({ > url: l.url ? String(l.url).trim() : '', > name: l.name ? String(l.name).trim() : '', > type: l.type ? String(l.type).trim() : '', > })) > .filter(l => l.url && l.name && l.type); > > // Add new link if not duplicate > const incoming = { url: rawUrl, name: finalName, type: finalType }; > const sig = l => `${l.url}::${l.type}::${l.name}`; > const seen = new Set(current.map(sig)); > if (!seen.has(sig(incoming))) current.push(incoming); > > obj.info[linkKey] = current.map(l => ({ url: l.url, name: l.name, type: l.type })); > > // Dump back to YAML > let updatedDescriptor; > try { > if (typeof YAML.dump === 'function') { > updatedDescriptor = YAML.dump(obj, { indent: 2, lineWidth: 120 }); > } else if (typeof YAML.stringify === 'function') { > updatedDescriptor = YAML.stringify(obj, { indent: 2 }); > } else { > throw new Error('YAML serializer not available.'); > } > } catch (err) { > throw new Error('Failed to serialize descriptor YAML: ' + err.message); > } > > // ✅ Return updatedDescriptor (not wrapped in {body=...}) > return { updatedDescriptor }; > > type: JAVASCRIPT > outgoingActions: > - create-or-update-entity > isRootAction: false > - name: Create or update entity > slug: create-or-update-entity > schema: > inputs: > body: "{{{actions.javascript.outputs.result.updatedDescriptor}}}" > dryRun: false > integrationAlias: null > actionIdentifier: cortex.createOrUpdateEntity > type: ADVANCED_HTTP_REQUEST > outgoingActions: [] > isRootAction: false > runRestrictionPolicies: [] > iconTag: SecurityCamera > variables: [] > ``` > > 2. Use the [Cortex CLI](https://pypi.org/project/cortexapps-cli/) to run this command, using the path to your Workflow YAML file: `cortex workflows create -f ` **Cortex UI** #### Step 1.1: Create the Workflow and configure basic settings 1. In Cortex, navigate to **Workflows**. In the upper right corner, click **+Create workflow**. Choose a blank Workflow. 2. Follow the documentation to [configure the basic settings for your Workflow](/streamline/workflows/create#creating-a-workflow). #### Step 1.2: Add blocks to the Workflow Add the following blocks to your Workflow: > **User input** > > Add a User Input block to collect the link type, link URL, and which entity to update. > > 1. Click **+** in the center of the page. In the block library modal, choose **User input**. > 2. In the block configuration side panel, enter a name and unique slug for this block. > * In this example, we use the name `User input` and the slug `user-input`. > 3. Click **+Add user input**. Add the following: > * **Name**: Link type > * **Key**: link-type > * **Type**: Select > * **Data source**: Manual > * **Options**: Click **+Add option** to add options for `Pen Test` and `Data Retention Policy`. > * Click **Add input**. > 4. Click **+Add user input**. Add the following: > * **Name**: Link URL > * **Key**: link-url > * **Type**: Text > * Click **Add input**. > 5. At the bottom of the side panel, click **Save**. > **Retrieve entity descriptor** > > This block retrieves the entity descriptor. > > 1. Click **+** in the center of the page. In the block library modal, select the **Cortex > Retrieve entity descriptor** block. > 2. In the side panel, enter a name and unique slug for the block. > * In this example, we use the name `Retrieve entity descriptor` and the slug `retrieve-entity-descriptor`. > 3. Configure the block: > * **Entity ID or tag**: `{{context.entity.tag}}` > 4. At the bottom of the side panel, click **Save**. > **JavaScript** > > This step retrieves the entity tag, validates required inputs, normalizes the data, and returns the updated link object in YAML format for use in the next Workflow block. > > 1. Click **+** in the center of the page. In the block library modal, select the **Cortex > Retrieve entity descriptor** block. > 2. In the side panel, enter a name and unique slug for the block. > * In this example, we use the name `JavaScript` and the slug `javascript`. > 3. In the text editor under the **JavaScript** header, enter the following: > > ```javascript theme={null} > const descriptor = actions['retrieve-entity-descriptor']?.outputs?.descriptor; > const linkType = actions['user-input']?.outputs?.['link-type']; > const linkUrl = actions['user-input']?.outputs?.['link-url']; > > if (!descriptor || typeof descriptor !== 'string') { > throw new Error('Descriptor must be a YAML string.'); > } > const rawType = String(linkType || '').trim(); > const rawUrl = String(linkUrl || '').trim(); > if (!rawType || !rawUrl) { > throw new Error('Both link-type and link-url are required.'); > } > > // Normalize input for mapping > const normalize = s => s.toLowerCase().replace(/[_\s-]+/g, ' ').trim(); > const normType = normalize(rawType); > > let finalType, finalName; > if (normType === 'pen test' || normType === 'pentest') { > finalType = 'pen-test'; > finalName = 'Pen Test'; > } else if (normType === 'data retention policy') { > finalType = 'documentation'; > finalName = rawType; // keep exactly what the user selected > } else { > finalType = rawType; > finalName = rawType; > } > > // Parse YAML > let obj; > try { > if (typeof YAML.load === 'function') { > obj = YAML.load(descriptor) || {}; > } else if (typeof YAML.parse === 'function') { > obj = YAML.parse(descriptor) || {}; > } else { > throw new Error('YAML parser not available in this runtime.'); > } > } catch (err) { > throw new Error('Failed to parse descriptor YAML: ' + err.message); > } > > // Ensure x-cortex-link exists > if (!obj.info) obj.info = {}; > const linkKey = 'x-cortex-link'; > const existing = obj.info[linkKey]; > obj.info[linkKey] = Array.isArray(existing) ? existing : (existing ? [existing] : []); > > // Normalize existing links > const current = obj.info[linkKey] > .filter(Boolean) > .map(l => ({ > url: l.url ? String(l.url).trim() : '', > name: l.name ? String(l.name).trim() : '', > type: l.type ? String(l.type).trim() : '', > })) > .filter(l => l.url && l.name && l.type); > > // Add new link if not duplicate > const incoming = { url: rawUrl, name: finalName, type: finalType }; > const sig = l => `${l.url}::${l.type}::${l.name}`; > const seen = new Set(current.map(sig)); > if (!seen.has(sig(incoming))) current.push(incoming); > > obj.info[linkKey] = current.map(l => ({ url: l.url, name: l.name, type: l.type })); > > // Dump back to YAML > let updatedDescriptor; > try { > if (typeof YAML.dump === 'function') { > updatedDescriptor = YAML.dump(obj, { indent: 2, lineWidth: 120 }); > } else if (typeof YAML.stringify === 'function') { > updatedDescriptor = YAML.stringify(obj, { indent: 2 }); > } else { > throw new Error('YAML serializer not available.'); > } > } catch (err) { > throw new Error('Failed to serialize descriptor YAML: ' + err.message); > } > > // ✅ Return updatedDescriptor (not wrapped in {body=...}) > return { updatedDescriptor }; > ``` > > 4. At the bottom of the side panel, click **Save**. > **Create or update entity** > > This block takes the object returned in the previous block and uses it to update the entity. > > 1. Click **+** in the center of the page. In the block library modal, select the **Cortex > Create or update entity** block. > 2. In the side panel, enter a name and unique slug for the block. > * In this example, we use the name `Create or update entity` and the slug `create-or-update-entity`. > 3. Configure the block: > * **Descriptor**: `{{{actions.javascript.outputs.result.updatedDescriptor}}}` > 4. At the bottom of the side panel, click **Save**. When you are finished adding blocks, click **Save workflow** in the upper right corner of the page. ### Step 2: Run the Workflow * In the [list of Workflows](https://app.getcortexapp.com/admin/workflows), locate the "Link SOC 2 Documents to Entity" Workflow and click **Run**. When you run the Workflow, the following events happen: 1. The Workflow pauses to collect a response from the user during the User Input block. The user selects an entity, then enters a link type and link URL. 2. The next step runs, retrieving the entity descriptor. 3. The JavaScript block runs, which does the following: 1. It retrieves the entity descriptor from the previous block, and it retrieves the link type and URL from the initial block. It validates that the required inputs exist. 2. It normalizes the link type. It parses the descriptor string into a JavaScript object. 3. It creates a new link object with url, name, and type, and it only adds the new link if it doesn't already exist. 4. It converts the updated object back to YAML format, and returns `{ updatedDescriptor }` for use in subsequent Workflow blocks. 4. The "Create or update entity" block runs, updating the entity with the `updatedDescriptor` output of the previous block. # Ensure SOC 2 compliance Source: https://docs.cortex.io/guides/compliance/soc2 Cortex enables streamlined SOC 2 compliance by eliminating manual, spreadsheet-based tracking and connecting real time system data to control verification. To improve consistency across your compliance tracking: * You can [launch a SOC 2 Compliance Scorecard](/guides/compliance/soc2#create-a-soc-2-scorecard). Cortex provides a prebuilt SOC 2 compliance [Scorecard](/standardize/scorecards) template that you can use to track audit-related controls and standards. * You can [launch an Initiative](/guides/compliance/soc2#create-a-soc-2-initiative) associated with the Scorecard, which gives your engineers a deadline for when to complete certain goals. * [Use reports and Cortex MCP](/guides/compliance/soc2#measuring-success) to better understand progress and next steps. ## Create a SOC 2 Scorecard ### Prerequisites Before using this Scorecard template: * Ensure you have configured integrations for: * Version control: [Azure DevOps](/ingesting-data-into-cortex/integrations/azuredevops), [Bitbucket](/ingesting-data-into-cortex/integrations/bitbucket), [GitHub](/ingesting-data-into-cortex/integrations/github), or [GitLab](/ingesting-data-into-cortex/integrations/gitlab). * [PagerDuty](/ingesting-data-into-cortex/integrations/pagerduty) * [Snyk](/ingesting-data-into-cortex/integrations/snyk) * This Scorecard uses Snyk for its vulnerability scanning rules, but the rules can be modified to check vulnerability data from [Checkmarx](/ingesting-data-into-cortex/integrations/checkmarx), [Mend](/ingesting-data-into-cortex/integrations/mend), [Semgrep](/ingesting-data-into-cortex/integrations/semgrep), [Veracode](/ingesting-data-into-cortex/integrations/veracode), or [Wiz](/ingesting-data-into-cortex/integrations/wiz). * See [CQL Explorer](https://app.getcortexapp.com/admin/queries) in your Cortex workspace for example queries for these integrations. * Ensure you have [created custom data fields](/ingesting-data-into-cortex/entities-overview/entities/custom-data) called `tls_enabled` and `last_risk_assessment_date`. ### Step 1: Create the Scorecard and configure its basic settings You can create a Scorecard in the Cortex UI, or you can add it to your workspace via GitOps or the Cortex API. **Cortex UI** #### Create Scorecard in the Cortex UI 1. On the [**Scorecards** page](https://app.getcortexapp.com/admin/scorecards) in your workspace, click **Create Scorecard**. 2. On the `SOC-2 Compliance` template, click **Use**. 3. Configure basic settings, including the Scorecard's name, unique identifier, description, and more. * Learn about configuring the basic settings in the [Creating a Scorecard documentation](/standardize/scorecards/create). **GitOps or API** #### Create Scorecard via GitOps or API When following a [GitOps approach](/configure/gitops), you can add a Scorecard YAML file to your `.cortex/scorecards` directory in your version control repository. Note that GitOps must be enabled for Scorecards in your [GitOps settings](/configure/settings/gitops-settings). You could also use the [Cortex API,](/api/rest/scorecards) where you can submit a Scorecard definition in YAML. > **SOC 2 Scorecard YAML** > > Use the YAML file below to add this Scorecard to your workspace via the API or via a GitOps flow. > > ```yaml theme={null} > tag: soc-2 > name: SOC 2 Compliance > description: |- > Ensure services meet SOC 2 requirements by tracking key security, operational, and maturity controls including ownership, TLS, vulnerability scans, and risk assessments. > > (Created from Scorecard template) > draft: false > notifications: > enabled: false > scoreDropNotificationsEnabled: false > exemptions: > enabled: true > autoApprove: false > userSpecificNotifications: false > ladder: > name: Default Ladder > levels: > - name: Foundational Security > rank: 1 > color: "#c38b5f" > - name: Operational Compliance > rank: 2 > color: "#8c9298" > - name: Advanced SOC 2 Maturity > rank: 3 > color: "#cda400" > rules: > - title: Pen test linked > expression: links("pen-test").length > 0 > identifier: 1ac74f97-0e8a-3d5c-bde2-f71890c34f6d > weight: 1 > level: Advanced SOC 2 Maturity > failureMessage: "Add a link of type pen-test by following the instructions in [our\ > \ docs](https://docs.cortex.io/ingesting-data-into-cortex/entities-overview/entities/external-docs#add-links-to-an-entity)." > - title: On-call is set > expression: oncall != null > identifier: 2a2e6d7e-9ea1-3df6-a2a1-8db501126d53 > weight: 1 > level: Foundational Security > failureMessage: "Add an on-call rotation by following the instructions in our docs\ > \ for the [on-call integration](https://docs.cortex.io/ingesting-data-into-cortex/integrations#on-call)\ > \ your team uses." > - title: Service has ownership > expression: ownership != null > identifier: 2d3e1a5a-2012-3b28-b561-dd31c73117aa > weight: 1 > level: Foundational Security > failureMessage: "Add an owner by following the instructions in [our docs](https://docs.cortex.io/ingesting-data-into-cortex/entities-overview/entities/ownership)." > - title: Service included in Risk Assessment in last year > expression: custom("last_risk_assessment_date").fromNow() > duration("P1Y") > identifier: 66283efc-364e-3b29-9f00-9fb4bcc6e785 > weight: 1 > level: Advanced SOC 2 Maturity > - title: TLS is enabled > expression: custom("tls_enabled") == true > identifier: 887c666a-09bd-3ab8-95e3-ff005e68563d > weight: 1 > level: Foundational Security > - title: Branch protection is set on default branch > expression: git.branchProtection("main") != null > identifier: 97cab18c-cd5b-3c66-baf3-4da2291cd022 > weight: 1 > level: Foundational Security > - title: Data retention policy linked > expression: links("document").filter((link) => link.name.matches("data-retention*")).length > > 0 > identifier: 9ebf4ee6-5af6-369b-8bb3-67365be7900f > weight: 1 > level: Operational Compliance > failureMessage: "Add a link of type document with a name that starts with data-retention\ > \ by following the instructions in [our docs](https://docs.cortex.io/ingesting-data-into-cortex/entities-overview/entities/external-docs#add-links-to-an-entity)." > - title: PR approval is required to merge > expression: git.numOfRequiredApprovals() > 0 > identifier: a148260a-81c3-3201-9692-de99fd08ed16 > weight: 1 > level: Foundational Security > - title: Vuln scan passing (med & high) > expression: "snyk.numOfIssues(severity=[\"HIGH\", \"CRITICAL\", \"MEDIUM\"]) <=\ > \ 0" > identifier: ce7d90a6-fa92-3bfb-9eaf-ab3bb3f1deb3 > weight: 1 > level: Operational Compliance > - title: Unit testing in place > expression: | > git.workflowRuns().filter((run) => run.name.matchesIn("Unit Test")).length > 0 > identifier: e5e9ecd2-683f-3b63-8da9-fdb807fbc736 > weight: 1 > level: Operational Compliance > - title: "Vuln scan passing (low, med & high)" > expression: "snyk.numOfIssues(severity=[\"HIGH\", \"CRITICAL\", \"MEDIUM\", \"LOW\"\ > ]) <= 0" > identifier: f7e0f628-cd94-3f08-aeb9-72b03565c5d7 > weight: 1 > level: Advanced SOC 2 Maturity > filter: > kind: GENERIC > types: > include: > - service > ``` ### Step 2: Review and modify rules Cortex's templated rules are based on common industry standards: > **Level 1: Foundational Security** > > * On-call is set\\ > > `oncall != null` > * Service has ownership\\ > > `ownership != null` > * TLS is enabled\\ > > `custom("tls_enabled") == true` > * Branch protection is set on default branch\\ > > `git.branchProtection("main") != null` > * PR approval is required to merge\\ > > `git.numOfRequiredApprovals() > 0` > **Level 2: Operational Compliance** > > * Data retention policy linked\\ > > `links("document").filter((link) => link.name.matches("data-retention*")).length > 0` > * Vulnerability scan passing (medium & high)\\ > > `snyk.numOfIssues(severity=["HIGH", "CRITICAL", "MEDIUM"]) <= 0` > * Unit testing in place\\ > > `git.workflowRuns().filter((run) => run.name.matchesIn("Unit Test")).length > 0` > **Level 3: Advanced SOC 2 Maturity** > > * Pen test linked\\ > > `links("pen-test").length > 0` > * Service included in Risk Assessment in last year\\ > > `custom("last_risk_assessment_date").fromNow() > duration("P1Y")` > * Vulnerability scan passing (low, medium, & high)\\ > > `snyk.numOfIssues(severity=["HIGH", "CRITICAL", "MEDIUM", "LOW"]) <= 0` You can reorder, delete, and edit rules, add more rules to a level, and assign more points to a rule to signify its importance. Behind each rule is a [Cortex Query Language (CQL) ](/standardize/cql)query; you can edit the existing CQL or write your own queries to further refine your rules. ## Create a SOC 2 Initiative Follow the steps below to create an Initiative: > **Create a SOC 2 Initiative** > > To motivate change by a certain deadline, you can create an Initiative: > > 1. While viewing your SOC 2 Compliance Scorecard, click **Create Initiative** in the upper right. > 2. Configure the Initiative fields, including a descriptive name so your team members understand the purpose of the Initiative. For example, `Ensure data retention policy is linked for all services`. > * Make sure to enable notifications so users are notified if an entity they own is failing the Initiative's goal. > 3. Save the Initiative. > > After the Initiative is published, entity owners will be notified if their entity is not meeting the goal. > > Learn more about [creating Initiatives in the docs](/improve/initiatives). ## Measuring success To understand progress of your Scorecard: * Ask [Cortex MCP,](/get-started/cortex-ai-assistant/mcp) "How is my SOC 2 Scorecard doing?" The MCP will respond with information on the entities that are failing rules and suggested next steps. * Review reports: The [Bird's Eye report](/improve/reports/birds-eye) gives insight into how entities are performing against the Scorecard by visualizing the data as a heat map:\ ![The bird's eye report shows Scorecard progress as a heatmap.](https://mintcdn.com/cortex-290c0c42/qRY2zZcIyXqFVeCq/guides/images/soc2-birds-eye-1.jpg?fit=max\&auto=format\&n=qRY2zZcIyXqFVeCq\&q=85\&s=78551fc1b6ce83a8e17151e294aab64a) You can also review your Engineering Intelligence metrics for impact on key engineering metrics, such as: * **MTTR**: With best practices in place, such as on-call rotation and ownership, you should see faster incident response. * **Deployment frequency**: Improved governance reduces rework and manual gates. Once baselines are set, you may see deployment frequency increasing. # Automate user access to Copilot Source: https://docs.cortex.io/guides/dev-onboarding/automate-user-access-to-copilot This Workflow automatically sets up developers with access to GitHub Copilot. In this example, approval from a specific team is required. Depending on your organization's requirements, you may want to configure a [User input](/streamline/workflows/blocks#configuring-a-core-block) block instead, effectively allowing users to self-serve access to GitHub Copilot without needing approval from a specific team. ### Prerequisites Before getting started: * Before calling the GitHub API endpoint in the Async HTTP request block, your organization must already be on Copilot Business or Enterprise and have seat management policies configured. * You must [create a secret in Cortex](/configure/settings/api-keys/secrets). * In this example, the secret in Cortex must be named `GITHUB_COPILOT_TOKEN`. ### Step 1: Start creating the Workflow Follow the steps in the documentation to [create a Workflow](/streamline/workflows/create) and [configure its basic settings](/streamline/workflows/create#creating-a-workflow). Note that Cortex has a pre-built template for this Workflow that contains the [Async HTTP request](/guides/dev-onboarding/automate-user-access-to-copilot#step-2-add-blocks-to-the-workflow) block. The example on this page includes an additional [Manual approval](/guides/dev-onboarding/automate-user-access-to-copilot#step-2-add-blocks-to-the-workflow) block that allows you to designate an approving team. Also in this example, the payload of the Async HTTP block includes `approver": "{{actions.manual-approval.outputs.actor}}`, which references the output of the Manual approval block. This reference is not included in the pre-built Workflow template. ### Step 2: Add blocks to the Workflow The instructions on this page describe how to create this Workflow in the Cortex UI, but it is also possible to copy the Workflow YAML and add it to your workspace via the [Cortex CLI](https://pypi.org/project/cortexapps-cli/). This allows you to quickly set up the example configuration then iterate on it for your own use case. Expand the tile below to learn more. > **Workflow YAML instructions** > > To upload the Workflow example YAML into your workspace: > > 1. Save the Workflow example YAML file below: > > ```yaml theme={null} > name: Approve access to GitHub Copilot > tag: copilot-access > description: "Get approval from the Platform team, then provision a seat in Copilot\ > \ for the user who initiates the Workflow run." > isDraft: true > filter: > type: GLOBAL > runResponseTemplate: "Successfully provisioned GitHub Copilot for {{context.initiatedBy.email}}" > failedRunResponseTemplate: "Failed to add a seat to GitHub Copilot for {{context.initiatedBy.email}}" > restrictActionCompletionToRunnerUser: false > actions: > - name: Manual approval > slug: manual-approval > schema: > approvingTeamIds: > - en319eca313083ac36 > approverDescription: null > type: MANUAL_APPROVAL > outgoingActions: > - asynchronous-http-request > isRootAction: true > - name: Asynchronous HTTP request > slug: asynchronous-http-request > schema: > headers: > Authorization: "Bearer {{ context.secrets.GITHUB_COPILOT_TOKEN }}" > httpMethod: POST > payload: |- > { > "inputs": {"email": "{{context.initiatedBy.email}}", "approver": "{{actions.manual-approval.outputs.actor}}", "callback": "{{callbackUrl}}", "github_user": "{{context.initiatedBy.identityMappings.github}}" }, > "ref": "main" > } > url: https://api.github.com/orgs/cortexapps/copilot/billing/selected_users > timeoutInSeconds: null > type: HTTP_REQUEST_ASYNC > outgoingActions: [] > isRootAction: false > runRestrictionPolicies: [] > iconTag: null > variables: [] > ``` > > 2. Use the [Cortex CLI](https://pypi.org/project/cortexapps-cli/) to run this command, using the path to your Workflow YAML file:\\ > > `cortex workflows create -f ` Expand the tiles below to learn about each block in this Workflow and how to configure them in the Cortex UI: > **Manual approval** > > In this block, you select which team has to give approval for the user to access GitHub Copilot. > > 1. Click **+** in the center of the page. In the block library modal, choose **Manual approval**. > 2. In the block configuration side panel, enter a name and unique slug for this block. > * In this example, we use the name `Manual approval` and the slug `manual-approval`. > 3. Under **Teams allowed to approve**, select the teams authorized to approve access to GitHub Copilot. > 4. Save the block. > **Async HTTP request** > > This block looks at the initiating user's [identity mapping](/configure/settings/managing-users/identity-mapping) in Cortex for GitHub, then calls the GitHub API to grant access to Copilot for that user. > > 1. Click **+** in the center of the page. In the block library modal, choose **Async HTTP request**. > 2. In the block configuration side panel, enter a name and unique slug for this block. > * In this example, we use the name `Grant access to Copilot` and the slug `copilot-access`. > 3. Configure the block: > * **HTTP method**: `POST` > * **URL**: Enter a URL for the request. > * In this example, we call the GitHub endpoint that adds users to your org's Copilot subscription: `https://api.github.com/orgs//copilot/billing/selected_users` > * **Headers**: `Authorization: Bearer {{ context.secrets.GITHUB_COPILOT_TOKEN }}` > * The token you configure must have [permissions to manage Copilot seats](https://docs.github.com/en/rest/copilot/copilot-user-management). > * In this example, the secret in Cortex must be named `GITHUB_COPILOT_TOKEN`. > * **Payload**: > > ```json theme={null} > { > "inputs": {"email": "{{context.initiatedBy.email}}", "approver": "{{actions.manual-approval.outputs.actor}}", "callback": "{{callbackUrl}}", "github_user": "{{context.initiatedBy.identityMappings.github}}" }, > "ref": "main" > } > ``` > > 4. Save the block. ### Step 3: Run the Workflow When you run the Workflow, the following events happen: * The Workflow pauses to collect a response from a member of one of the teams specified during the Manual approval block. * After a user gives their approval, the Async HTTP request block runs. It uses the initiator of the Workflow as the GitHub user, then makes a call to the GitHub API to provision access to Copilot for that user. # Automate user access to GitHub, PagerDuty, and Jira Source: https://docs.cortex.io/guides/dev-onboarding/automate-user-access-to-github-pagerduty-and-jira This Workflow automatically sets up new developers with access to GitHub, PagerDuty, and Jira. #### Step 1: Start creating the Workflow [#step-1-start-creating-the-workflow](#step-1-start-creating-the-workflow) Follow the steps in the documentation to [create a Workflow](/streamline/workflows/create) and [configure its basic settings](/streamline/workflows/create#creating-a-workflow). #### Step 2: Add blocks to the Workflow [#step-2-add-blocks-to-the-workflow](#step-2-add-blocks-to-the-workflow) The instructions on this page describe how to create this Workflow in the Cortex UI, but it is also possible to copy the Workflow YAML and add it to your workspace via the [Cortex CLI](https://pypi.org/project/cortexapps-cli/). This allows you to quickly set up the example configuration then iterate on it for your own use case. Expand the tile below to learn more. > **Workflow YAML instructions** > > To upload the Workflow example YAML into your workspace: > > 1. Save the Workflow example YAML file below: > > ```yaml theme={null} > name: "Dev Onboarding: User Access" > tag: dev-onboarding-user-access > description: "Automatically sets up new developers with access to GitHub, PagerDuty,\ > \ and Jira." > isDraft: false > filter: > type: GLOBAL > runResponseTemplate: null > failedRunResponseTemplate: null > restrictActionCompletionToRunnerUser: false > actions: > - name: Get GH Username > slug: get-gh-username > schema: > inputs: > - name: GitHub Username > description: Enter your personal GitHub username. > key: github-username > required: false > defaultValue: null > placeholder: null > validationRegex: "^[^\\s]+$" > type: INPUT_FIELD > inputOverrides: [] > type: USER_INPUT > outgoingActions: > - add-user-to-org > isRootAction: true > - name: Add user to GH org > slug: add-user-to-org > schema: > inputs: > org: cortexapps > role: member > username: actions.get-gh-username.outputs.github-username > integrationAlias: cortex > actionIdentifier: github.addUserToOrg > type: ADVANCED_HTTP_REQUEST > outgoingActions: > - add-user-to-pd > isRootAction: false > - name: Add user to PagerDuty > slug: add-user-to-pd > schema: > headers: > Accept: application/vnd.pagerduty+json;version=2 > Authorization: "Bearer {{context.secrets.pd_token}}" > httpMethod: POST > payload: |- > { > "user": { > "type": "user", > "name": "{{context.initiatedBy.name}}", > "email": "{{context.initiatedBy.email}}" > } > } > url: https://api.pagerduty.com/users > type: HTTP_REQUEST > outgoingActions: > - add-user-to-jira > isRootAction: false > - name: Add user to Jira > slug: add-user-to-jira > schema: > headers: {} > httpMethod: POST > payload: |- > { > "emailAddress": "{{context.initiatedBy.email}}", > "displayName": "{{context.initiatedBy.name}}" > }` > url: https://cortex.atlassian.net/rest/api/3/user > type: HTTP_REQUEST > outgoingActions: > - send-message > isRootAction: false > - name: Send message > slug: send-message > schema: > channel: social > message: "{{context.initiatedBy.name}} has been added to GitHub, PagerDuty, and\ > \ Jira." > type: SLACK > outgoingActions: [] > isRootAction: false > runRestrictionPolicies: [] > iconTag: AndroidLogo > variables: [] > > ``` > > 2. Use the [Cortex CLI](https://pypi.org/project/cortexapps-cli/) to run this command, using the path to your Workflow YAML file:\\ > > `cortex workflows create -f ` Expand the tiles below to learn about each block in this Workflow and how to configure them in the Cortex UI: > **User input** > > In this example, we add a User Input block to obtain the user's GitHub username. > > 1. Click **+** in the center of the page. In the block library modal, choose **User input**. > 2. In the block configuration side panel, enter a name and unique slug for this block. > 1. In this example, we use the name `Get GH Username` and the slug `get-gh-username`. > 3. Click **+Add user input**. Add the following: > * **Name**: GitHub Username > * **Key**: github-username > * **Description**: Enter your personal GitHub username. > * **Type**: Text > * Click **Add input**. > 4. At the bottom of the side panel, click **Save**. > **Add user to GitHub org** > > This block adds a user to a GitHub organization. > > 1. Click **+** in the center of the page. In the block library modal, select the **GitHub > Add user to org** block. > 2. In the side panel, enter a name and unique slug for the block. > * In this example, we use the name `Add user to GH org` and the slug `add-user-to-org`. > 3. Configure the block: > * **Alias**: Choose which GitHub configuration to use. > * **Organization**: Enter your GitHub organization name. > * **Username**: Enter the handle for the user's GitHub account. > * In our example, we use templating to take the output of the previous step and set it as the value for this field: `actions.get-gh-username.outputs.github-username` > * **Role**: Select the role of the user in the organization. > 4. At the bottom of the side panel, click **Save**. > **HTTP requests** > > There are two HTTP requests that perform the following actions: Adding the user to PagerDuty and adding the user to Jira. > > **Add the user to PagerDuty** > > 1. Click **+** in the center of the page. In the block library modal, select the **HTTP request** block. > 2. In the side panel, enter a name and unique slug for the block. > * In this example, we use the name `Add user to PagerDuty` and the slug `add-user-to-pd`. > 3. Configure the block: > 1. **HTTP method**: POST > 2. **URL**: In our example, we set this to `https://api.pagerduty.com/users`. > 3. **Headers**: Set the following headers: > * `Accept`: `application/vnd.pagerduty+json;version=2` > * `Authorization`: `Bearer {{ context.secrets.pd_token }}` > 4. **Payload**: In our example, we enter the following: > > ```json theme={null} > { > "user": { > "type": "user", > "name": "{{context.initiatedBy.name}}", > "email": "{{context.initiatedBy.email}}" > } > } > ``` > > 4. Save the block. > > **Add the user to Jira** > > 1. Click **+** in the center of the page. In the block library modal, select the **HTTP request** block. > 2. In the side panel, enter a name and unique slug for the block. > * In this example we use the name `Add user to Jira` and the slug `add-user-to-jira`. > 3. Configure the block: > 1. **HTTP method**: POST > 2. **URL**: In our example, we set this to:\\ > > `https://cortex.atlassian.net/rest/api/3/user` > 3. **Payload**: In our example, we enter the following: > > ```json theme={null} > { > "emailAddress": "{{context.initiatedBy.email}}", > "displayName": "{{context.initiatedBy.name}}" > }` > ``` > > 4. Save the block. > **Slack message** > > In this step, we send a templated message via Slack informing the user that they have been added to GitHub, PageryDuty, and Jira. > > 1. Click **+** in the center of the page. In the block library modal, select the **Slack** block. > 2. In the side panel, enter a name and unique slug for the block. > * In this example we use the name `Send message` and the slug `send-message`. > 3. Select a Slack channel name. > 4. Enter text for the message that will be sent via Slack. In our example, we use the following: > > ``` > {{context.initiatedBy.name}} has been added to GitHub, PagerDuty, and Jira. > ``` > > 5. Save the block. #### Step 3: Run the Workflow [#step-3-run-the-workflow](#step-3-run-the-workflow) When you run the Workflow, the following events happen: * The Workflow pauses to collect a response from the user during the User Input block. * The "Add user to org" block runs. It uses the output of the previous block as the username, then automatically adds to that user to the specified GitHub org. * The first HTTP request runs. Using the name and email address of the user who initiated the Workflow, it creates a user in PagerDuty. * The second HTTP request runs. Using the name and email address of the user who initiated the Workflow, it creates a user in Jira. * The Slack block runs, which sends a Slack message to the user to let them know that their GitHub, PagerDuty, and Jira accounts are ready. # Automate new dev environment Source: https://docs.cortex.io/guides/dev-onboarding/env-setup-workflow This example automates the creation of a GitHub repository, infrastructure provisioning with Terraform, and generates a PR for setting up an RDS instance. ### Step 1: Register the Scaffolder templates This Workflow uses two Scaffolder templates: * [Hello Org Template](https://github.com/cortex-workshops/hello-org-template) * [Terraform RDS Template](https://github.com/cortex-workshops/terraform-rds-template) Follow the instructions to [register the Scaffolder templates in Cortex](/streamline/workflows/scaffolder). ### Step 2: Start creating the Workflow Follow the steps in the documentation to [create a Workflow](/streamline/workflows/create) and [configure its basic settings](/streamline/workflows/create#creating-a-workflow). ### Step 3: Add blocks to the Workflow The instructions on this page describe how to create this Workflow in the Cortex UI, but it is also possible to copy the Workflow YAML and add it to your workspace via the [Cortex CLI](https://pypi.org/project/cortexapps-cli/). This allows you to quickly set up the example configuration then iterate on it for your own use case. Expand the tile below to learn more. > **Workflow YAML instructions** > > To upload the Workflow example YAML into your workspace: > > 1. Save the Workflow example YAML file below: > > ```yaml theme={null} > name: "Dev Onboarding: Environment Setup" > tag: dev-onboarding-env-setup > description: "This workflow automates the creation of a GitHub repository, infrastructure\ > \ provisioning with Terraform, and generates a PR for setting up an RDS instance." > isDraft: false > filter: > type: GLOBAL > runResponseTemplate: null > failedRunResponseTemplate: null > restrictActionCompletionToRunnerUser: false > actions: > - name: Transform User Info > slug: transform-user-info > schema: > expression: .context.initiatedBy.name + "-repo" > type: JQ > outgoingActions: > - scaffold-hello-org > isRootAction: true > - name: Scaffold Hello Org Repo > slug: scaffold-hello-org > schema: > scaffolderTemplateId: st363f187d3e1a826e > createNewRepository: true > createService: null > inputOverrides: > - inputKey: repo_name > outputVariable: actions.transform-user-info.outputs.result > editable: false > type: VALUE > type: SCAFFOLDER > outgoingActions: > - trigger-workflow > isRootAction: false > - name: Terraform Infrastructure Provisioning > slug: trigger-workflow > schema: > inputs: > ref: main > repo: cortex-workshops/terraform > inputs: "{\"user\": \"{{context.initiatedBy.name}}\"}" > workflow_id: .github/workflows/main.yaml > integrationAlias: cortex > actionIdentifier: github.createWorkflowDispatchEvent > type: ADVANCED_HTTP_REQUEST > outgoingActions: > - scaffold-rds-terraform > isRootAction: false > - name: Open PR with RDS terraform > slug: scaffold-rds-terraform > schema: > scaffolderTemplateId: st363f198d56473124 > createNewRepository: false > createService: null > inputOverrides: > - inputKey: publisherRepoFullName > outputVariable: actions.scaffold-hello-org.outputs.response.gitURL > editable: false > type: VALUE > type: SCAFFOLDER > outgoingActions: > - notify-developer > isRootAction: false > - name: Notify Developer > slug: notify-developer > schema: > channel: all-es-testing > message: "Hi, {{context.initiatedBy.name}}! Your new test environment is ready\ > \ to go!" > type: SLACK > outgoingActions: [] > isRootAction: false > runRestrictionPolicies: [] > iconTag: Keyboard > variables: [] > ``` > > 2. Use the [Cortex CLI](https://pypi.org/project/cortexapps-cli/) to run this command, using the path to your Workflow YAML file:\\ > > `cortex workflows create -f ` Expand the tiles below to learn about each block in this Workflow and how to configure them in the Cortex UI: > **Data transformation** > > Create a data transformation to take the Workflow initiator's name and append `-repo` to it: > > 1. Click **+** in the center of the page. In the block library modal, choose **Data transformation**. > 2. In the block configuration side panel, enter a name and unique slug for this block. > 1. In this example, we use the name `Transform user info` and the slug `transform-user-info`. > 3. Add a jq expression to take the initiator's name and add `-repo` to it: > > ```jq theme={null} > .context.initiatedBy.name + "-repo" > ``` > > 4. At the bottom of the side panel, click **Save**. > **Scaffolder** > > This block creates a new repository in your connected Git integration, using templating to apply the output of the previous block to the Scaffolder configuration. > > 1. Click **+** in the center of the page. In the block library modal, select the **Scaffolder** block. > 2. In the side panel, enter a name and unique slug for the block. > 1. In this example, we use the name `Scaffold Hello Org Repo` and the slug `scaffold-hello-org`. > 3. Under **Scaffolder template**, select your template. In this example, we use `Hello Org Template`. > 4. Select the option to **Create a new repo**. > 5. Add override variables. The **Variable** dropdown pulls in all the variables that are able to be overridden in the Git provider and in the Scaffolder template. In this example, we apply the following override: > * **repo\_name**: `actions.transform-user-info.outputs.result` > * This overrides the Repo Name field with the output of the "Transform user info" block earlier in the Workflow. > 6. At the bottom of the side panel, click **Save**. > **Trigger GitHub workflow** > > This block triggers Terraform infrastructure in GitHub. > > 1. Click **+** in the center of the page. In the block library modal, select the **GitHub > Trigger workflow** block. > 2. In the side panel, enter a name and unique slug for the block. > * In this example, we use the name `Terraform Infrastructure Provisioning` and the slug `trigger-workflow`. > 3. Configure the block: > * **Repository**: Enter your repository name. > * **Ref**: Enter the Git reference to trigger the workflow on, e.g. `main`. > * **Workflow ID or file name**: Enter the ID of the GitHub workflow or the file name of the workflow file. > * In our example, we added `main.yaml`. Note that this should be just the file name and not the path to the file. > * **Inputs**: Optionally enter key-value pairs to pass to the workflow. > * In our example, we added: `{"user": "{{context.initiatedBy.name}}"}` > 4. At the bottom of the side panel, click **Save**. > **Scaffolder** > > This block opens a Pull Request to set up an RDS instance, using templating to apply the output of the previous block to the Scaffolder configuration. > > 1. Click **+** in the center of the page. In the block library modal, select the **Scaffolder** block. > 2. In the side panel, enter a name and unique slug for the block. > 1. In this example, we use the name `Open PR with RDS terraform` and the slug `scaffold-rds-terraform`. > 3. Under **Scaffolder template**, select your template. In this example, we use `Terraform RDS Template`. > 4. Select the option to **Open a pull request**. > 5. Add override variables. The **Variable** dropdown pulls in all the variables that are able to be overridden in the Git provider and in the Scaffolder template. In this example, we apply the following override: > * **publisherRepoFullName**: `actions.scaffold-hello-org.outputs.response.gitURL` > * This overrides the Repo Name field with the output of the "Scaffold Hello Org Repo" block earlier in the Workflow. > 6. At the bottom of the side panel, click **Save**. > **Slack message** > > In this step, we send a templated message via Slack informing the user that their test environment is ready. > > 1. Click **+** in the center of the page. In the block library modal, select the **Slack** block. > 2. In the side panel, enter a name and unique slug for the block. > * In this example we use the name `Notify developer` and the slug `notify-developer`. > 3. Select a Slack channel name. > 4. Enter text for the message that will be sent via Slack. In our example, we use the following: > > ``` > Hi, {{context.initiatedBy.name}}! Your new test environment is ready to go! > ``` > > 5. Save the block. ### Step 4: Run the Workflow When you run the Workflow, the following events happen: * The Data transformation block runs, which produces a repository name for the user based on your specified naming convention. * The Scaffolder runs, creating a new repository. The repo's name is based on the output of the previous block. * The GitHub "Trigger a workflow" block runs, which provisions Terraform infrastructure. * The second Scaffolder block runs, which opens a Pull Request to set up an RDS instance. * The Slack block runs, which sends a Slack message to the user to let them know that their test environment is ready. # Measure DORA progress Source: https://docs.cortex.io/guides/dora/scorecard In Cortex, use Scorecards to measure progress against DORA benchmarks at your organization, and use the Eng Intelligence [DORA Dashboard](/improve/eng-intelligence/dora-dashboard) to see your metrics improve in realtime. ## DORA Metrics Scorecard example In this example, assume that you have launched a DORA Metrics Scorecard based on the out-of-the-box template provided in Cortex. > **To launch this Scorecard** > > 1. Click **Scorecards** from the main nav in Cortex. > 2. In the upper right corner, click **Create Scorecard**. In the `DORA Operational Readiness` template tile, click **Use**. > > ![Click Create Scorecard, then select DORA Metrics.](https://mintcdn.com/cortex-290c0c42/qRY2zZcIyXqFVeCq/guides/images/click-dora.jpg?fit=max\&auto=format\&n=qRY2zZcIyXqFVeCq\&q=85\&s=05fb3ff99beb26c75559ffcecea2aa7e) ### DORA performance levels Cortex's DORA Scorecard template is based on the established DORA standards of performance. ### Scorecard rules The Scorecard contains four levels: Minimum, Established, Accelerating, and Elite. Each level corresponds with increasingly higher performance against DORA standards. ![Each level in the DORA Scorecard contains rules that show success against DORA metric benchmarks.](https://mintcdn.com/cortex-290c0c42/qRY2zZcIyXqFVeCq/guides/images/dora-scorecard-img.jpg?fit=max\&auto=format\&n=qRY2zZcIyXqFVeCq\&q=85\&s=f6093fcdddfc56bfe978aed1a45ef6c1) Expand the tile below to learn about how the rules in each level give you insight into your team's performance. > **DORA Scorecard rules** > > The progress your team makes against these rules allows you to assess the agility, stability, and quality of your software delivery process. > > #### Minimum > > These rules help you establish a baseline of readiness to start measuring DORA metrics. > > * Logs are linked > * Ownership is set > * Version control (Git) is in place > * Documentation is present > > #### Established > > These rules motivate your teams to achieve DORA's Medium-level benchmarks for key metrics. > > * MTTR is less than 12 hours > * Deployment frequency is at least 2x/month > * Lead time for changes less than 5 days > * Change failure rate: \<30% of deployments are rollbacks > * Basic monitoring in place > * CI/CD pipeline configured > > #### Accelerating > > These rules motivate your teams to achieve DORA's High-level benchmarks for key metrics. > > * MTTR less than 4 hours > * Deployment frequency is at least 6x/month > * Lead time for changes less than 3 days > * Change failure rate: \<20% of deployments are rollbacks > * Metrics dashboard embedded > * Pipeline success rate => 85% > > #### Elite > > These rules motivate your teams to achieve DORA's Elite-level benchmarks for key metrics. > > * MTTR less than 1 hour > * Deployment frequency is 30+ per month > * Lead time for changes is less than 1 day > * Change failure rate: \<10% of deployments are rollbacks > * SLOs are defined > * Pipeline success rate => 95% ### Understanding Scorecard levels Assume the following for an entity: * It's passing 3/4 rules in the Minimum level * It has logs linked, ownership set, and a version control integration configured (passing) * It does not have documentation linked (failing) * It's passing all rules in the Established level In this case, the entity would have **No Level**. * It is failing the rule "Documentation is present" in the Minimum level. Because of this, it has not fully achieved the Minimum level, the first one that an entity can pass. * Once the entity has documentation linked, it will achieve all rules in the Minimum level. Because it is already passing all rules required for the Established level, this means it will automatically achieve the Established level. > [!TIP] > > This kind of gamification motivates developers to not only progress through the levels, but to maintain the quality of their entities over time. ### Driving continuous improvement against DORA benchmarks Measuring your performance against DORA standards does not start and stop with launching a Scorecard. We recommend taking the steps described below to understand your baseline, motivate change, and continuously improve: **1. Measure baseline metrics** Measure your metrics in the [DORA Dashboard](/improve/eng-intelligence/dora-dashboard). **2. Investigate** Drill down into underlying data in [Data Explorer](/improve/eng-intelligence/data-explorer). **3. Take action** Codify expectations by launching a [Scorecard](/standardize/scorecards), allowing you to continuously evaluate entities against standards using live data from integrated tools. **4. Validate impact** Review your [DORA Dashboard](/improve/eng-intelligence/dora-dashboard) to see improved metrics, validating the impact of the DORA Metrics Scorecard. # Reduce MTTA Source: https://docs.cortex.io/guides/incident-mgmt/reduce-mtta Mean Time to Acknowledge (MTTA) measures how quickly teams acknowledge an incident after it is triggered. Reducing MTTA depends on: * Operational readiness: Ensuring the right people are reachable at all times. * Response behavior: Tracking and improving how fast incidents are acknowledged once triggered. A well-designed Scorecard shouldn't just track MTTA as a number; **it should validate the conditions that enable low MTTA**, such as on-call setup, contact methods, and escalation policy depth. ### Best practices When creating a Scorecard aimed at reducing MTTA, follow these best practices: * Group rules by functional area (e.g., Incident Response, Monitoring, Reliability) to simplify assessment. * Keep evaluation windows aligned so that related signals trend together. * Enable Cortex notifications for when overall Scorecard scores drop, prompting teams to review and act. ## Rules that focus on reducing MTTA | Category | Purpose | Example CQL expression | | - | - | - | | On-call configuration | Ensure service has an active PagerDuty schedule | `oncall != null` | | Contact reliability | Verify responders can be reached through multiple channels | `oncall.usersWithoutContactMethods(allowed=["EMAIL","PHONE","PUSH_NOTIFICATION","SMS"]) == 0` | | Escalation depth | Require at least two escalation tiers | `oncall.numOfEscalations() >= 2` | | Acknowledgment time | Track MTTA against defined thresholds | `jq(oncall.analysis(...), '.meanSecondsToFirstAck <= 300')` | | Monitoring coverage | Ensure critical services have active alerting rules | `datadog.monitors().length > 0` | | SLO tracking | Validate that a service has defined SLOs and error budgets | `slos().any((slo) => slo.name.matchesIn(".*Uptime.*"))` | | Ownership coverage | Require that every service has a defined owning team | `ownership != null` | | Communication channel is set | Require that every service has a defined communication channel | `slack != null and slack.numOfMembers() > 0` | | Entity was verified in the last 90 days | Require entity information, including ownership, on-call, and Slack to be verified in the last 90 days | `verifications().lastVerifiedAt() != null and verifications().lastVerifiedAt().fromNow() > duration("P-90D")` | | Entity does not have pending verifications | Ensure entity does not have any pending verifications | `verifications().verifications().any(verification => verification.status == "PENDING") == 0` | ## Examples from real Cortex users The following anonymized examples come from real uses cases our customers are solving with Cortex. ### Event Readiness Scorecard For companies that have a busy season (e.g., companies that are busier during Black Friday), they might create a [seasonal readiness Scorecard](/guides/production-readiness/seasonal-readiness-scorecard) in Cortex. The following strategy ties performance metrics directly to readiness controls: * Track MTTA \< 120 seconds for P1 and P2 incidents * Require two-tier escalation policies in PagerDuty:\ `oncall.numOfEscalations() >= 2` * Validate that on-call users have valid contact methods configured:\ `oncall.usersWithoutContactMethods(...) == 0` * Combine outcome metrics (MTTA) with configuration checks to ensure teams can meet targets consistently. ### On-call Configuration Scorecard The following strategy ensures every service can be reached before an incident occurs, eliminating the common MTTA outliers caused by misconfigured alerts: * Verify that on-call rotations exist\ `oncall != null` * Validate that on-call users have valid contact methods configured:\ `oncall.usersWithoutContactMethods(...) == 0` * Flag services without assigned responders This CQL applies to all on-call integrations: [Opsgenie](/ingesting-data-into-cortex/integrations/opsgenie), [PagerDuty](/ingesting-data-into-cortex/integrations/pagerduty), [Splunk On-Call (formerly VictorOps)](/ingesting-data-into-cortex/integrations/splunk-oncall), and [xMatters](/ingesting-data-into-cortex/integrations/xmatters). ### Operational Maturity Scorecard The previous examples applies to services and other entities. Some organizations prefer to track team-level operational maturity, including incident management as one area of assessment. The following strategy aims for low MTTA as part of a broader operational maturity, not an isolated performance goal: * Measure operational behaviors like post-incident reviews, ownership clarity, and alert hygiene. * Focus on consistent response patterns rather than single-point metrics. # Reduce MTTR Source: https://docs.cortex.io/guides/incident-mgmt/reduce-mttr Mean Time to Resolution (MTTR) measures how quickly systems are restored after an incident begins. Reducing MTTR depends on: * Operational readiness: Clear ownership, actionable runbooks, and reliable on-call escalations ensure the right people are reachable at all times. * Repair effectiveness: Tracking and improving how fast incidents are resolved and ensuring Cortex Workflows are configured to rollback, restart, scale up pods, and other processes you use during incidents. * See an example Workflow: [Rollback a service during an incident](/guides/incident-mgmt/workflow-rollback) A well-designed Scorecard shouldn't just track MTTR as a number; **it should validate the conditions that enable low MTTR**, such as up-to-date runbooks, ownership, and on-call coverage with escalation depth. ### Best practices When creating a Scorecard aimed at reducing MTTR, follow these best practices: * Group rules by functional area (e.g., Incident Response, Observability, Reliability) to make gaps obvious. * Keep evaluation windows aligned so that related signals trend together. * Enable Cortex notifications for when overall Scorecard scores drop, prompting teams to review and act. ## Rules that focus on reducing MTTR | Category | Purpose | Example CQL expression | | - | - | - | | On-call configuration | Ensure service has an active PagerDuty schedule | `oncall != null` | | Contact reliability | Verify responders can be reached through multiple channels | `actMethods(allowed=["EMAIL","PHONE","PUSH_NOTIFICATION","SMS"]) == 0` | | Ownership coverage | Require that every service has a defined owning team | `ownership != null` | | Monitoring coverage | Ensure critical services have active alerting rules | `datadog.monitors().length > 0` | | SLO tracking | Ensure SLOs exist for latency | `slos().filter((slo) => slo.name.matchesIn("latency") and slo.sliValue >= 0.9999).length > 0` | | Ownership coverage | Require that every service has a defined owning team | `ownership != null` | | Alerting channel configured | Require that a Slack or Microsoft Teams channel is configured for each service | `slack != null` | | Runbooks configured | Require that a runbook is linked so responders have clear steps to follow | `links("runbook").length > 0` | | MTTR benchmarks | Target benchmarks for MTTR: In lower levels of a Scorecard, you might target \<90 minutes, and in higher levels you might target \<30 minutes | `oncall.analysis(lookback = duration("P30D")).meanSecondsToResolve < 1800` | | CI/CD pipeline configured | Require a CI/CD pipeline to exist so deployments can be automated and repeatable. | `git.fileExists(".gitlab-ci.yml")` | | Pipeline success rate | Ensure builds are passing successfully, showing stable automation and tests. You might target 85-95%. | `git.percentBuildSuccess() >= 0.95` | ### Launch an Incident Preparedness Scorecard Cortex offers a pre-built Scorecard for Incident Preparedness. You can launch this Scorecard to improve your incident processes, enabling a reduced MTTR. ## Example: LetsGetChecked Cortex customer LetsGetChecked used Cortex to automatically sync service and resource catalogs, enabling their team to quickly find accurate service information. They used Scorecards to drive operational excellence for onboarding, service maturity, and deployment frequency. ### Impact They reduced MTTR by 67% and doubled their deployment frequency. ### Learn more Learn more in the case study: [How LetsGetChecked doubled deployment frequency and slashed MTTR by 67% with Cortex](https://www.cortex.io/case-studies/letsgetchecked). ## Example: H\&R Block H\&R block used Cortex to automate manual, repetitive tasks that were draining velocity and morale. ### Impact They reduced MTTR from up to 24 hours to less than one hour. ### Learn more Learn more in the Cortex blog: [How H\&R Block automated the toil out of its developer experience](https://www.cortex.io/post/how-hr-block-automated-the-toil-out-of-developer-experience). # Create ServiceNow incident Source: https://docs.cortex.io/guides/incident-mgmt/servicenow After [integrating Cortex with ServiceNow](/ingesting-data-into-cortex/integrations/servicenow), you can create Workflows to trigger ServiceNow actions, create tickets, or update records. This guide describes how to use a Workflow to create a ServiceNow incident. ## How to automate ServiceNow incident creation in Cortex ### Prerequisites Before getting started: * [Create the following secrets](/configure/settings/api-keys/secrets) in Cortex: * A ServiceNow access token named `servicenow_token` * A token for name of your ServiceNow domain named `servicenow_domain` * You must have the `Edit Workflows` [permission](/configure/settings/managing-users/permissioning) to create the Workflow, and the `Execute Workflow runs` permission to run it. ### Step 1: Create the Workflow You can create a Workflow in the Cortex UI or via the Cortex CLI. **Cortex CLI** #### Add the Workflow via CLI You can use the [Cortex CLI](https://pypi.org/project/cortexapps-cli/) to add the example Workflow to your workspace. This allows you to quickly set up the example configuration then iterate on it for your own use case. Expand the tile below to learn more: > **Import the Workflow via CLI** > > 1. Save the Workflow example YAML file below: > > ```yaml theme={null} > name: Create ServiceNow Incident > tag: create-servicenow-incident-2bed57cd-fcf4-40ed-a916-0857f9748ff0 > description: "This template allows you to create a ServiceNow incident from Cortex.\ > \ \nThe following fields are included, but you can add more:\n* Short Description\n\ > * Description\n* Severity\n\nThe workflow will use the email from the user running\ > \ the workflow to set the `opened by` field. If the workflow is run from an entity's\ > \ context and it has an `x-cortex-servicenow.service.id`, the incident is associated\ > \ to the CI in ServiceNow. This assumes that the service was imported from the `cmdb_ci_service`\ > \ table in ServiceNow.\n\nThis workflow requires that you set up the following secrets\ > \ in the [Secrets settings page](/admin/settings/secrets):\n* ServiceNow access\ > \ token: (servicenow_token)\n* Name of ServiceNow domain: (servicenow_domain)\n\n\ > Failure to do so will result in errors when running the workflow." > isDraft: true > filter: > entityFilter: > typeFilter: > types: > - service > entityGroupFilter: null > ownershipScope: ALL > type: ENTITY > runResponseTemplate: null > failedRunResponseTemplate: null > restrictActionCompletionToRunnerUser: false > actions: > - name: Incident details > slug: incident-details > schema: > inputs: > - name: Short description > description: null > key: short-description > required: true > defaultValue: null > placeholder: null > validationRegex: null > type: INPUT_FIELD > - name: Description > description: null > key: description > required: true > defaultValue: null > placeholder: null > validationRegex: null > type: TEXTAREA_FIELD > - name: Severity > description: null > key: severity > required: true > options: > - "1" > - "2" > - "3" > - "4" > - "5" > optionsLabels: null > defaultValue: null > placeholder: null > allowAdditionalOptions: false > type: SELECT_FIELD > - name: Urgency > description: null > key: urgency > required: false > options: > - 1 - High > - 2 - Medium > - 3 - Low > optionsLabels: null > defaultValue: null > placeholder: null > allowAdditionalOptions: false > type: SELECT_FIELD > - name: Impact > description: null > key: impact > required: false > options: > - 1 - High > - 2 - Medium > - 3 - Low > optionsLabels: null > defaultValue: null > placeholder: null > allowAdditionalOptions: false > type: SELECT_FIELD > inputOverrides: [] > jsValidatorScript: null > type: USER_INPUT > outgoingActions: > - get-user-sys-id > isRootAction: true > - name: Get User Sys_ID > slug: get-user-sys-id > schema: > headers: > Authorization: "Basic {{ context.secrets.servicenow_token }}" > httpMethod: GET > payload: null > url: "https://{{context.secrets.servicenow_domain}}.service-now.com/api/now/table/sys_user?sysparm_query=email%3D{{context.initiatedBy.email}}&sysparm_limit=10" > type: HTTP_REQUEST > outgoingActions: > - extract-user-sys-id > isRootAction: false > - name: Extract User Sys ID > slug: extract-user-sys-id > schema: > expression: ".actions.\"get-user-sys-id\".outputs.body.result[0].sys_id" > type: JQ > outgoingActions: > - get-sysid-of-service > isRootAction: false > - name: Get SysID of Service > slug: get-sysid-of-service > schema: > expression: .context.entity.descriptor > type: JQ > outgoingActions: > - extract-service-sys-id > isRootAction: false > - name: Extract Service Sys ID > slug: extract-service-sys-id > schema: > expression: ".actions.\"get-sysid-of-service\".outputs.result.info.\"x-cortex-servicenow\"\ > .services[0].id" > type: JQ > outgoingActions: > - create-incident > isRootAction: false > - name: Create Incident > slug: create-incident > schema: > headers: > Content-Type: application/json;charset=UTF-8 > Authorization: "Basic {{ context.secrets.servicenow_token }}" > httpMethod: POST > payload: "{\"short_description\":\"{{actions.incident-details.outputs.short-description}}\"\ > ,\"description\":\"{{actions.incident-details.outputs.description}}\",\"opened_by\"\ > :\"{{actions.extract-user-sys-id.outputs.result}}\",\"severity\":\"{{actions.incident-details.outputs.severity}}\"\ > ,\"business_service\":\"{{actions.extract-service-sys-id.outputs.result}}\"\ > , \"urgency\":\"{{actions.incident-details.outputs.urgency}}\", \"impact\":\"\ > {{actions.incident-details.outputs.impact}}\"}" > url: "https://{{context.secrets.servicenow_domain}}.service-now.com/api/now/table/incident" > type: HTTP_REQUEST > outgoingActions: [] > isRootAction: false > runRestrictionPolicies: [] > iconTag: null > variables: [] > ``` > > 2. Use the [Cortex CLI](https://pypi.org/project/cortexapps-cli/) to run this command, using the path to your Workflow YAML file: `cortex workflows create -f ` **Cortex UI** #### Select the template and save 1. In Cortex, navigate to **Workflows**. In the upper right corner, click **+Create workflow**. 2. Locate the template for "Create ServiceNow Incident." Click **+Use**. 3. Edit the Workflow as needed. * The User Input block is configured to ask the user for short description, description, severity, urgency, and impact. All fields except for "impact" are set to be required. You can adjust this per field. 4. In the upper right corner of the page, click **Save workflow**. ### Step 2: Run the Workflow * In the [list of Workflows](https://app.getcortexapp.com/admin/workflows), locate the "Create ServiceNow incident" Workflow and click **Run**. When you run the Workflow, the following events happen: 1. The Workflow pauses to collect a response from the user during the User Input block. The user enters a short description, description, severity, urgency, and impact. 2. The HTTP Request block runs, which obtains the ServiceNow Sys\_ID of the user who initiated the Workflow in Cortex. 3. The Data transformation blocks run, transforming the data to get the Sys\_ID of the service and its entity descriptor from Cortex. 4. In the final HTTP Request block, it sends a payload to the ServiceNow API including the information entered by the user during the first step, and the data that was pulled from the SysID and entity descriptor. An incident is opened in ServiceNow. ## Install Cortex's ServiceNow Incidents plugin To further highlight visibility of ServiceNow incidents in Cortex, you can also [install the ServiceNow Incidents plugin](/streamline/plugins/marketplace#installing-a-plugin-from-the-cortex-plugin-marketplace). After installing, you can view incidents within a ServiceNow tab directly on an [entity's details page](/ingesting-data-into-cortex/entities-overview/entities/details): ![ServiceNow incidents are displayed under a tab on an entity details page.](https://mintcdn.com/cortex-290c0c42/qRY2zZcIyXqFVeCq/guides/images/servicenow-plugin.jpg?fit=max\&auto=format\&n=qRY2zZcIyXqFVeCq\&q=85\&s=f1096ffb79b780153aa30fb5b500d4ff) # Rollback a service during an incident Source: https://docs.cortex.io/guides/incident-mgmt/workflow-rollback You can use a Cortex Workflow to roll back services, allowing quick remediation in the event of incidents. ## How to rollback a service with a Cortex Workflow ### Step 1: Start creating the Workflow Follow the steps in the documentation to create a Workflow and configure its basic settings. This Workflow is scoped to the "service" entity type. ### Step 2: Add blocks to the Workflow The instructions on this page describe how to create this Workflow in the Cortex UI, but it is also possible to copy the Workflow YAML and add it to your workspace via the [Cortex CLI](https://pypi.org/project/cortexapps-cli/). This allows you to quickly set up the example configuration then iterate on it for your own use case. Expand the tile below to learn more. > **Workflow YAML instructions** > > To upload the Workflow example YAML into your workspace: > > 1. Save the Workflow example YAML file below: > > ```yaml theme={null} > name: Rollback Service > tag: workflow-0e405a5d-6a1c-41a6-84a8-d3287941c000 > description: null > isDraft: true > filter: > entityFilter: > typeFilter: > types: > - service > entityGroupFilter: null > ownershipScope: ALL > type: ENTITY > runResponseTemplate: null > failedRunResponseTemplate: null > restrictActionCompletionToRunnerUser: false > actions: > - name: Get incident info > slug: get-incident-info > schema: > inputs: > - name: Incident Name > description: null > key: incident-name > required: false > defaultValue: null > placeholder: null > validationRegex: null > type: INPUT_FIELD > - name: Incident Severity > description: null > key: incident-severity > required: false > options: > - SEV0 > - SEV1 > - SEV2 > optionsLabels: null > defaultValue: null > placeholder: "" > allowAdditionalOptions: false > type: SELECT_FIELD > - name: Create Incident Slack Channel? > description: null > key: create-incident-slack-channel > required: true > defaultValue: false > type: TOGGLE_FIELD > inputOverrides: [] > type: USER_INPUT > outgoingActions: > - list-deployments-for-entity > isRootAction: true > - name: List deployments for entity > slug: list-deployments-for-entity > schema: > inputs: > page: 0 > entityId: "{{context.entity.tag}}" > pageSize: 2 > integrationAlias: null > actionIdentifier: cortex.getDeploysForEntity > type: ADVANCED_HTTP_REQUEST > outgoingActions: > - javascript > isRootAction: false > - name: Format deployments > slug: javascript > schema: > script: "// Assume \"deployments\" is the JSON from the previous step\nconst deployments\ > \ = actions['list-deployments-for-entity'].outputs.response.deployments\n\n\ > // Create a flat array of strings formatted for a dropdown\nconst shasFormatted\ > \ = deployments.map(dep => \n `${dep.title} (${dep.sha.slice(0,7)}) - ${dep.timestamp}`\n\ > );\n\n// Also return the raw SHAs if needed for later steps\nconst shas = deployments.map(dep\ > \ => dep.sha);\n\nreturn {\n totalDeployments: deployments.length,\n deployments:\ > \ deployments, // full objects if you need them\n shas: shas, \ > \ // raw SHA values\n shasFormatted: shasFormatted // flat\ > \ string array for dropdowns\n};" > type: JAVASCRIPT > outgoingActions: > - user-input > isRootAction: false > - name: User input > slug: user-input > schema: > inputs: > - name: Commit ID to rollback to > description: null > key: commit-id-to-rollback-to > required: false > options: [] > optionsLabels: null > defaultValue: null > placeholder: null > allowAdditionalOptions: false > type: SELECT_FIELD > inputOverrides: > - inputKey: commit-id-to-rollback-to > outputVariable: actions.javascript.outputs.result.shasFormatted > type: OPTION > type: USER_INPUT > outgoingActions: > - extract-sha > isRootAction: false > - name: Extract SHA > slug: extract-sha > schema: > script: |- > // The selected option from the User Input block > const selectedOption = actions['user-input'].outputs['commit-id-to-rollback-to'] > > // Extract the text between parentheses > const match = selectedOption.match(/\((.*?)\)/); > const sha = match ? match[1] : null; > > return { > selectedOption: selectedOption, // full string > sha: sha // extracted commit SHA > }; > type: JAVASCRIPT > outgoingActions: > - trigger-workflow > isRootAction: false > - name: Trigger workflow > slug: trigger-workflow > schema: > inputs: > ref: main > repo: cortex-workshops/deployment > inputs: |- > { > "service": "{{context.entity.tag}}", > "rollback_to": "{{actions.extract-sha.outputs.result.sha}}" > } > workflow_id: rollback.yaml > integrationAlias: cortex > actionIdentifier: github.createWorkflowDispatchEvent > type: ADVANCED_HTTP_REQUEST > outgoingActions: > - branch > isRootAction: false > - name: Branch > slug: branch > schema: > branches: > - name: Create incident Slack channel > slug: create-incident-slack-channel-path > outgoingAction: create-incident-slack-channel > expression: "actions[\"get-incident-info\"].outputs[\"create-incident-slack-channel\"\ > ] == true" > type: CONDITIONAL > - name: Do not create Slack channel > slug: do-not-create-slack-channel > outgoingAction: send-fyi-message > expression: "actions[\"get-incident-info\"].outputs[\"create-incident-slack-channel\"\ > ] == false" > type: CONDITIONAL > fallbackBranch: null > joiningAction: null > type: CONDITIONAL_BRANCH > outgoingActions: > - create-incident-slack-channel > - send-fyi-message > isRootAction: false > - name: Create Incident Slack Channel > slug: create-incident-slack-channel > schema: > headers: > Content-Type: application/json > Authorization: "Bearer {{context.secrets.apiKey}}" > httpMethod: POST > payload: |- > { > "name": "incident-{{actions.get-incident-info.outputs.incident-name}}" > } > url: https://slack.com/api/conversations.create > type: HTTP_REQUEST > outgoingActions: > - send-slack-message > isRootAction: false > - name: Send FYI message > slug: send-fyi-message > schema: > channel: public-channel > message: "Service {{context.entity.tag}} with incident does not have a separate Slack channel." > type: SLACK > outgoingActions: [] > isRootAction: false > - name: Send Slack Message > slug: send-slack-message > schema: > headers: > Content-Type: application/json > Authorization: "Bearer {{context.secrets.apiKey}}" > httpMethod: POST > payload: |- > { > "channel": "incident-{{actions.get-incident-info.outputs.incident-name}}", > "text": "Rollbacked service {{context.entity.tag}} to commit ID {{actions.extract-sha.outputs.result.sha}}." > } > url: https://slack.com/api/chat.postMessage > type: HTTP_REQUEST > outgoingActions: [] > isRootAction: false > runRestrictionPolicies: [] > iconTag: null > variables: [] > ``` > > 2. Use the [Cortex CLI](https://pypi.org/project/cortexapps-cli/) to run this command, using the path to your Workflow YAML file:\\ > > `cortex workflows create -f ` Expand the tiles below to learn about each block in this Workflow and how to configure them in the Cortex UI: > **User input** > > In this example, we add a User Input block to obtain information about an incident. > > 1. Click **+** in the center of the page. In the block library modal, choose **User input**. > 2. In the block configuration side panel, enter a name and unique slug for this block. > 1. In this example, we use the name `Get Incident info` and the slug `get-incident-info`. > 3. Click **+Add user input**. Add the following: > * **Name**: Incident Name > * **Key**: incident-name > * **Type**: Text > * Click **Add input**. > 4. Click **+Add user input**. Add the following: > * **Name**: Incident Severity > * **Key**: incident-severity > * **Type**: Select > * **Options**: Click **+Add option** to add options for the severity labels. In our example, we use `SEV0`, `SEV1`, and `SEV2`. > * Click **Add input**. > 5. Click **+Add user input**. Add the following: > * **Name**: Create incident Slack channel? > * **Key**: create-incident-slack-channel > * **Type**: Toggle > * **Default value**: False > * Click **Add input**. > 6. At the bottom of the side panel, click **Save**. > **List deployments for entity** > > This block lists the deployments for an entity. > > 1. Click **+** in the center of the page. In the block library modal, select the **Cortex > List deployments for entity** block. > 2. In the side panel, enter a name and unique slug for the block. > * In this example, we use the name `List deployments for entity` and the slug `list-deployments-for-entity`. > 3. Configure the block: > * **Page size**: In our example, we configured `2`. > 4. At the bottom of the side panel, click **Save**. > **JavaScript** > > This block uses JavaScript to format the deployments. > > 1. Click **+** in the center of the page. In the block library modal, select the **JavaScript** block. > 2. In the side panel, enter a name and unique slug for the block. > * In this example, we use the name `Format Deployments` and the slug `javascript`. > 3. In the **JavaScript** text editor box, enter an expression. Our example uses the following: > > ```javascript theme={null} > /*#CORTEX_IGNORE*/import {_, YAML, hcl, context, actions, variables, fetch} from './utils.js'; async () => { > // Assume "deployments" is the JSON from the previous step > const deployments = actions['list-deployments-for-entity'].outputs.response.deployments > > // Create a flat array of strings formatted for a dropdown > const shasFormatted = deployments.map(dep => > `${dep.title} (${dep.sha.slice(0,7)}) - ${dep.timestamp}` > ); > > // Also return the raw SHAs if needed for later steps > const shas = deployments.map(dep => dep.sha); > > return { > totalDeployments: deployments.length, > deployments: deployments, // full objects if you need them > shas: shas, // raw SHA values > shasFormatted: shasFormatted // flat string array for dropdowns > }; > /*#CORTEX_IGNORE*/} > ``` > > 4. Save the block. > **User input** > > This block asks the user for the commit ID to roll back to, pulling the commit IDs from the previous step. > > 1. Click **+** in the center of the page. In the block library modal, select the **User input** block. > 2. In the side panel, enter a name and unique slug for the block. > * In this example we use the name `User input` and the slug `user-input`. > 3. Click +Add user input. Add the following: > * **Name**: Commit ID to rollback to > * **Key**: commit-id-to-rollback-to > * **Type**: Select > * **Data source**: Manual > * Click **Add input**. > * **Path to override value**: Enter `actions.javascript.outputs.result.shasFormatted`. > 4. Save the block. > **JavaScript** > > This block uses JavaScript to extract the SHA that was selected in the previous step. > > 1. Click **+** in the center of the page. In the block library modal, select the **JavaScript** block. > 2. In the side panel, enter a name and unique slug for the block. > * In this example, we use the name `Extract SHA` and the slug `extract-sha`. > 3. In the **JavaScript** text editor box, enter an expression. Our example uses the following: > > ```javascript theme={null} > /*#CORTEX_IGNORE*/import {_, YAML, hcl, context, actions, variables, fetch} from './utils.js'; async () => { > // The selected option from the User Input block > const selectedOption = actions['user-input'].outputs['commit-id-to-rollback-to'] > > // Extract the text between parentheses > const match = selectedOption.match(/\((.*?)\)/); > const sha = match ? match[1] : null; > > return { > selectedOption: selectedOption, // full string > sha: sha // extracted commit SHA > }; > /*#CORTEX_IGNORE*/} > ``` > > 4. Save the block. > **Trigger GitHub workflow** > > This block triggers a GitHub workflow to roll back the deployment. > > 1. Click **+** in the center of the page. In the block library modal, select the **GitHub > Trigger workflow** block. > 2. In the side panel, enter a name and unique slug for the block. In this example, we use the name `Trigger workflow` and the slug `trigger-workflow`. > 3. Configure the block: > * **Repository**: Enter your repository name. > * **Ref**: Enter the Git reference to trigger the workflow on, e.g. `main`. > * **Workflow ID or file name**: Enter the ID of the GitHub workflow or the file name of the workflow file. > * In our example, we added `rollback.yaml`. > * **Inputs**: Optionally enter key-value pairs to pass to the workflow. > * In our example, we added: > > ```json theme={null} > { > "service": "{{context.entity.tag}}", > "rollback_to": "{{actions.extract-sha.outputs.result.sha}}" > } > ``` > 4. At the bottom of the side panel, click **Save**. > > This block's `response` output includes `workflow_run_id`, `run_url`, and `html_url` for the triggered GitHub Actions run. You can reference these in later blocks, for example to poll the run's status or include a link to the run in a Slack message. > **Branch** > > During the first User input step, the user can choose whether or not to create a Slack channel for the incident. Their choice determines which path will be followed during the Branch block. > > If they chose to create an incident Slack channel: > > 1. Click **+** in the center of the page. In the block library modal, choose **Branch**. > 2. In the block configuration side panel, enter a name and unique slug for this block. > * In this example, we use the name `Branch` and the slug `branch`. > 3. Click +Add path. Configure the conditional path: > * **Name**: Create incident Slack channel > * **Slug**: create-incident-slack-channel-path > * **Path expression**: `actions["get-incident-info"].outputs["create-incident-slack-channel"] == true` > * Save the path. > 4. Click **+Add path**. Configure the conditional path: > * **Name**: Do not create Slack channel > * **Slug**: do-not-create-slack-channel > * **Path expression**: `actions["get-incident-info"].outputs["create-incident-slack-channel"] == false` > * Save the path. > 5. Save the block. > > #### Add blocks to the "Create incident Slack channel" path > > **HTTP requests** > > 1. Click **+** under the new path. In the block library modal, choose **HTTP request**. > 2. In the block configuration side panel, enter a name and unique slug for this block. > * In this example, we use the name `Create incident Slack channel` and the slug `create-incident-slack-channel`. > 3. Configure the block: > * **HTTP method**: POST > * **URL**: `https://slack.com/api/conversations.create` > * **Headers**: > * `Content-Type: application/json` > * `Authorization: Bearer {{context.secrets.apiKey}}` > * **Payload**: In our example, we enter the following: > > ```json theme={null} > { > "name": "incident-{{actions.get-incident-info.outputs.incident-name}}" > } > ``` > > 4. Save the block. > 5. Click **+** under the path. In the block library modal, choose **HTTP request**. > 6. In the block configuration side panel, enter a name and unique slug for this block. In this example, we use the name `Send Slack message` and the slug `send-slack-message`. > 7. Configure the block: > 1. **HTTP method**: POST > 2. **URL**: `https://slack.com/api/conversations.create` > 3. **Headers**: > * `Content-Type: application/json` > * `Authorization: Bearer {{context.secrets.apiKey}}` > 4. **Payload**: In our example, we enter the following: > > ``` > { > "channel": "incident-{{actions.get-incident-info.outputs.incident-name}}", > "text": "Rollbacked service {{context.entity.tag}} to commit ID {{actions.extract-sha.outputs.result.sha}}." > } > ``` > > 8. Save the block. > > **Add block to the "Do not create Slack channel" path** > > 1. Click **+** under the new path. In the block library modal, choose **Slack > Send message**. > 2. In the block configuration side panel, enter a name and unique slug for this block. > * In this example, we use the name `Send FYI message` and the slug `send-fyi-message`. > 3. Configure the block: > * **Slack channel name**: Select the channel where you want to send a message informing the team that you did not create a separate Slack channel for the incident. > * **Message text**: In our example, we set this to:\\ > > `Service {{context.entity.tag}} with incident does not have a separate Slack channel.` > 4. Save the block. ### Step 3: Run the Workflow * At the top of the page, click **Run Workflow**. When you run the Workflow, the following events happen: 1. The Workflow pauses to collect a response from the user during the User Input block. The user enters a name and severity for the incident, and chooses whether to create a Slack channel * Some incidents require additional team work and collaboration, while others can be easily mitigated and may not require a dedicated channel. 2. The "List deployments for entity" block runs, fetching a list of deployments associated with the entity. 3. The JavaScript block runs, which formats the deployment data. 4. The next User Input block runs, which uses the formatted data from the previous block to provide a commit ID to rollback to. 5. The second JavaScript block runs, which extracts the SHA from the output of the previous block. 6. The GitHub workflow is triggered to roll back the affected service. 7. The Branch block runs: * If the user selected to create a Slack channel: An HTTP request runs to create an incident Slack channel, and an HTTP block runs to send a Slack message into the channel including the incident name, the service being rolled back, and the commit ID. * If the user selected to not create a Slack channel: The "Do not create Slack channel" path runs. A Slack block runs, which sends a Slack message to an existing team channel to let them know a separate incident channel was not created. # Accelerate migration to K8s Source: https://docs.cortex.io/guides/migrations-and-modernization/accelerate-migration-to-k8s Organizations migrate to Kubernetes because it solves critical scalability, reliability, security, and developer-velocity challenges that modern teams face. At its core, Kubernetes provides a standardized, automated, self-healing platform for running applications. Accelerating a Kubernetes migration is often a strategic engineering decision made to meet certain business requirements, such as lowering infrastructure costs or improving MTTR, in a shorter timeframe. To accelerate a migration to Kubernetes: * [Launch a Kubernetes Deployment Baseline Scorecard](/guides/migrations-and-modernization/accelerate-migration-to-k8s#create-a-kubernetes-scorecard). Cortex provides a prebuilt Kubernetes [Scorecard](/standardize/scorecards) template that you can use to track migration-related controls and standards. * [Launch an Initiative](/guides/migrations-and-modernization/accelerate-migration-to-k8s#create-a-k8s-acceleration-initiative) associated with the Scorecard, which gives your engineers a deadline for when to complete certain goals. * [Use reports and Cortex MCP](/guides/migrations-and-modernization/accelerate-migration-to-k8s#measuring-success) to better understand progress and next steps. > [!TIP] > > Cortex customer LetsGetCheck cut their Kubernetes migration timeline from 24 months down to 16 months by targeting goals with Initiatives. [Read the full case study here](https://www.cortex.io/case-studies/letsgetchecked). ## Create a Kubernetes Scorecard ### Prerequisites Before using this Scorecard template: * Ensure you have configured integrations for: * Version control: [Azure DevOps](/ingesting-data-into-cortex/integrations/azuredevops), [Bitbucket](/ingesting-data-into-cortex/integrations/bitbucket), [GitHub](/ingesting-data-into-cortex/integrations/github), or [GitLab](/ingesting-data-into-cortex/integrations/gitlab). * [Kubernetes](/ingesting-data-into-cortex/integrations/kubernetes) ### Step 1: Create the Scorecard and configure its basic settings You can create a Scorecard in the Cortex UI, or you can add it to your workspace via GitOps or the Cortex API. **Cortex UI** #### Create Scorecard in the Cortex UI 1. On the [**Scorecards** page](https://app.getcortexapp.com/admin/scorecards) in your workspace, click **Create Scorecard**. 2. On the `Kubernetes Deployment Baseline` template, click **Use**. 3. Configure basic settings, including the Scorecard's name, unique identifier, description, and more. * Learn about configuring the basic settings in the [Creating a Scorecard documentation](/standardize/scorecards/create). **GitOps or API** #### Create Scorecard via GitOps or API When following a [GitOps approach](/configure/gitops), you can add a Scorecard YAML file to your `.cortex/scorecards` directory in your version control repository. Note that GitOps must be enabled for Scorecards in your [GitOps settings](/configure/settings/gitops-settings). You could also use the [Cortex API,](/api/rest/scorecards) where you can submit a Scorecard definition in YAML. > **Kubernetes Scorecard YAML** > > Use the YAML file below to add this Scorecard to your workspace via the API or via a GitOps flow. > > ```yaml theme={null} > tag: kubernetes-deployment-baseline > name: Kubernetes Deployment Baseline > description: |- > This Scorecard enforces a minimum set of standards for services running on Kubernetes. It validates resource requests/limits, probes, container image hygiene, and Git branch protection so that workloads are reliable, predictable, and safe to operate in production. > draft: true > notifications: > enabled: true > scoreDropNotificationsEnabled: false > exemptions: > enabled: true > autoApprove: false > userSpecificNotifications: false > ladder: > name: Default Ladder > levels: > - name: Foundational container hygiene > rank: 1 > description: The service is at least containerized in a basic way. > color: "#c38b5f" > - name: Runtime ready > rank: 2 > description: This container behaves predictably when scheduled on Kubernetes. > color: "#8c9298" > - name: Kubernetes production ready > rank: 3 > description: This service is safe to run in production from a governance and reliability > perspective. > color: "#cda400" > rules: > - title: Memory limit is set > description: "Prevents a single pod from consuming all node memory. To ensure all\ > \ containers have memory limits set, this rule compares the total number of containers\ > \ with the number of containers that have memory limits." > expression: |- > jq(k8s.spec(), "[.[].template.spec.containers[]] | length") == > jq(k8s.spec(), "[.[].template.spec.containers[] | select(.resources.limits.memory != null)] | length") > identifier: 17376f1a-bfbe-361b-86d7-eac192f729d9 > weight: 1 > level: Runtime ready > - title: Git branch protection > description: Prevent direct pushes and unsafe merges to the main branch; enforce > reviews and status checks. > expression: git.branchProtection() != null > identifier: 21c30af3-6dd6-3bce-bbe5-56e43549015f > weight: 1 > level: Kubernetes production ready > failureMessage: Configure Git branch protection. > - title: CPU request is set > description: "This rule checks if CPU resource requests are defined for all containers\ > \ in your Kubernetes deployments, which is important for: \n- Kubernetes scheduler\ > \ to properly place pods on nodes\n- CPU throttling behavior (requests affect\ > \ CPU shares)\n- Cluster capacity planning\n- QoS classification (along with limits\ > \ and memory requests)\n\nTo ensure all containers have CPU resource requests,\ > \ this rule compares the total number of containers with the number of containers\ > \ that have CPU resource requests." > expression: |- > jq(k8s.spec(), "[.[].template.spec.containers[]] | length") == > jq(k8s.spec(), "[.[].template.spec.containers[] | select(.resources.requests.cpu != null)] | length") > identifier: 22d76d97-33a5-358a-8694-cf35909acc71 > weight: 1 > level: Runtime ready > - title: Memory request is set > description: "Prevents a single pod from consuming all node memory. To ensure all\ > \ containers have memory limits set, this rule compares the total number of containers\ > \ with the number of containers that have memory limits." > expression: "jq(k8s.spec(), \"[.[].template.spec.containers[]] | length\") == \n\ > jq(k8s.spec(), \"[.[].template.spec.containers[] | select(.resources.requests.memory\ > \ != null)] | length\")" > identifier: 46f4d17e-ceab-37dd-9a64-ddac9ee4aa73 > weight: 1 > level: Runtime ready > - title: Runs in cluster > description: This indicates operational use of Kubernetes. > expression: k8s != null > identifier: 6cfcc6f2-53ea-3da8-afaf-8659177d1896 > weight: 1 > level: Foundational container hygiene > - title: No "latest" tag for base image > description: |- > This is a best practice rule that ensures all base images have explicit version tags instead of using `:latest`, which: > - Prevents unpredictable builds when `:latest` changes > - Ensures build reproducibility > - Makes it clear what version is being used > expression: "git.fileContents(\"Dockerfile\").matchesIn(\"^FROM[ \\t]+(?!.*:latest\\\ > b).*$\")" > identifier: 873c36b3-5a18-3a09-9c58-bff967ffd6bd > weight: 1 > level: Kubernetes production ready > - title: Liveness probe is set > description: |- > This ensures your services have liveness probes configured, which are critical for: > > - Detecting when a container is stuck or deadlocked > - Automatically restarting unhealthy containers > - Improving service reliability and reducing MTTR > - Preventing containers that are "running" but not actually functioning > > To ensure all containers have liveness probes, this rule compares the total number of containers with the number of containers that have liveness probes. > expression: |- > jq(k8s.spec(), "[.[].template.spec.containers[]] | length") == > jq(k8s.spec(), "[.[].template.spec.containers[] | select(.livenessProbe != null)] | length") > identifier: b1f477fc-2ec5-39b0-9d48-b9a2922d7623 > weight: 1 > level: Runtime ready > - title: Readiness probe is set > description: |- > Ensures the service defines a Kubernetes readiness probe so that traffic is only routed to containers that are fully initialized and able to serve requests. A readiness probe prevents the service mesh or load balancer from sending user traffic to a pod that is still starting up, misconfigured, or temporarily degraded. This improves request success rates, reduces startup-induced errors, and helps maintain overall service reliability. > > To ensure all containers have readiness probes, this rule compares the total number of containers with the number of containers that have readiness probes. > expression: "jq(k8s.spec(), \"[.[].template.spec.containers[]] | length\") == jq(k8s.spec(),\ > \ \"[.[].template.spec.containers[] | select(.readinessProbe != null)] | length\"\ > )" > identifier: b4bed489-db7d-3566-826a-c78f6da22190 > weight: 1 > level: Runtime ready > failureMessage: "This service does not have a Kubernetes readiness probe configured.\ > \ Without a readiness probe, the load balancer may send traffic to pods before\ > \ they are ready, leading to failed requests and degraded reliability. Add a readiness\ > \ probe to ensure only healthy, ready pods receive traffic." > - title: Dockerignore file exists > description: Keep images lean and builds fast by excluding unnecessary files. > expression: git.fileExists(".dockerignore") > identifier: deb30726-2692-3a2d-8858-a828d33fea17 > weight: 1 > level: Foundational container hygiene > - title: Dockerfile exists > description: Verify the service is containerized using a maintained Dockerfile. > This enables consistency across different environments. > expression: git.fileExists("Dockerfile") > identifier: df928975-90e7-35ab-a05c-67ca7cb034a2 > weight: 1 > level: Foundational container hygiene > filter: > kind: GENERIC > types: > include: > - service > ``` ### Step 2: Review and modify rules Cortex's templated rules are based on common industry standards. See the template in-app for more context on each rule: > **Level 1: Foundational container hygiene** > > * Runs in cluster\\ > > `k8s != null` > * Dockerignore file exists\\ > > `git.fileExists(".dockerignore")` > * Dockerfile exists\\ > > `git.fileExists("Dockerfile")` > **Level 2: Runtime ready** > > * Memory request is set\\ > > `jq(k8s.spec(), "[.[].template.spec.containers[]] | length") == jq(k8s.spec(), "[.[].template.spec.containers[] | select(.resources.requests.memory != null)] | length")` > * Memory limit is set\\ > > `jq(k8s.spec(), "[.[].template.spec.containers[]] | length") == jq(k8s.spec(), "[.[].template.spec.containers[] | select(.resources.limits.memory != null)] | length")` > * Liveness probe is set\\ > > `jq(k8s.spec(), "[.[].template.spec.containers[]] | length") == jq(k8s.spec(), "[.[].template.spec.containers[] | select(.livenessProbe != null)] | length")` > * Readiness probe is set\\ > > `jq(k8s.spec(), "[.[].template.spec.containers[]] | length") == jq(k8s.spec(), "[.[].template.spec.containers[] | select(.readinessProbe != null)] | length")` > * CPU request is set\\ > > `jq(k8s.spec(), "[.[].template.spec.containers[]] | length") == jq(k8s.spec(), "[.[].template.spec.containers[] | select(.resources.requests.cpu != null)] | length")` > **Level 3: Kubernetes production ready** > > * Git branch protection\\ > > `git.branchProtection() != null` > * No "latest" tag for base image\\ > > `git.fileContents("Dockerfile").matchesIn("^FROM[ \t]+(?!.*:latest\b).$")` You can reorder, delete, and edit rules, add more rules to a level, and assign more points to a rule to signify its importance. Behind each rule is a [Cortex Query Language (CQL) ](/standardize/cql)query; you can edit the existing CQL or write your own queries to further refine your rules. ## Create a K8s acceleration Initiative If you notice the team isn't making progress as quickly as expected, or you need to complete certain rules within a specific timeframe, you can create an Initiative to motivate completion. Follow the steps below to create an Initiative: > **Create a Kubernetes Initiative** > > 1. While viewing your Kubernetes Deployment Baseline Scorecard, click **Create Initiative** in the upper right. > 2. Configure the Initiative fields, including a descriptive name so your team members understand the purpose of the Initiative. For example, `Accelerate K8s migration`. > * Make sure to enable notifications so users are notified if an entity they own is failing the Initiative's goal. > * For the goal, you might want to ask your team to complete a certain level, or specific rules. Examples: `Complete all "Runtime ready" level rules by the end of the quarter` or `Make sure a Dockerfile exists for every service by end of month`. > 3. Save the Initiative. > > After the Initiative is published, entity owners will be notified if their entity is not meeting the goal. They will see action items listed on their [engineering homepage](/streamline/homepage) and they will automatically receive a weekly progress update from the Initiative. > > Learn more about [creating Initiatives in the docs](/improve/initiatives). ## Measuring success To understand progress of your Scorecard: * Ask [Cortex MCP,](/get-started/cortex-ai-assistant/mcp) "How is my Kubernetes Deployment Baseline Scorecard doing?" The MCP will respond with information on the entities that are failing rules and suggested next steps. * Review reports: The [Bird's Eye report](/improve/reports/birds-eye) gives insight into how entities are performing against the Scorecard by visualizing the data as a heat map:\ ![The bird's eye report shows Scorecard progress as a heat map.](https://mintcdn.com/cortex-290c0c42/qRY2zZcIyXqFVeCq/guides/images/kubernetes-birds-eye.jpg?fit=max\&auto=format\&n=qRY2zZcIyXqFVeCq\&q=85\&s=e8de31484db809953274df430021a857) You can also review your Engineering Intelligence metrics for impact on key engineering metrics, such as: * **MTTR**: Kubernetes best practices, such as liveness probes in place, can result in faster diagnosis and auto-recovery. You may see MTTR decrease. * **Change failure rate**: With resource limits reducing pod crashes and no "latest" image tag resulting in deterministic builds, you may see more successful deploys on first attempt, thus decreasing change failure rate. # Manage an Upcoming EOL for AWS Source: https://docs.cortex.io/guides/migrations-and-modernization/manage-an-upcoming-eol-for-aws AWS maintains End of Life calendars for RDS, Lambda and Elasticache. Risks of not upgrading and running an unsupported version include forced upgrades, frozen configurations (no changes possible), and ineligibility for technical support and security patches. You can use a Cortex Scorecard to define and track the progress of your entities migrating to newer versions of RDS, Lambda, and Elasticache. When implemented, the Scorecard in this guide helps you identify services that have or have not yet upgraded. You can create Scorecards via [API, GitOps](/guides/migrations-and-modernization/manage-an-upcoming-eol-for-aws#create-aws-eol-scorecard-via-api-or-gitops), or the [Cortex UI](/guides/migrations-and-modernization/manage-an-upcoming-eol-for-aws#create-aws-eol-scorecard-in-the-cortex-ui). ## Create AWS EOL Scorecard via API or GitOps When following a GitOps approach, you can add a Scorecard YAML file to your `.cortex/scorecards` directory in your version control repository. Note that GitOps must be enabled for Scorecards in your GitOps settings. You could also use the Cortex API, where you can submit a Scorecard definition in YAML. > **AWS EOL Scorecard YAML** > > Use the YAML file below to add this Scorecard to your workspace via the API or via a GitOps flow. > > ```yaml theme={null} > description: >- > > AWS maintains End of Life calendars for RDS, Lambda and Elasticache. > > > Risk of not upgrading and running an unsupported version includes forced upgrade, frozen configuration ( no changes possible) . ineligibility for technical support and security patches. > name: "! EOL Upcoming - AWS" > rules: > - description: null > expression: > (jq(aws.details(), ".resources[0].engine") == "aurora-postgresql" AND jq(aws.details(), ".resources[0].engineVersion | startswith(\"13.\")") == true) > OR > (jq(aws.details(), ".resources[0].engine") == "aurora-mysql" AND jq(aws.details(), ".resources[0].engineVersion | startswith(\"8.\")") == true) > failureMessage: null > filter: > category: RESOURCE > query: entity_descriptor.info.`x-cortex-type` = "rds" > level: null > title: PostgreSQL EOL Version Upgrade Completed > weight: 10 > - description: null > expression: (jq(aws.details(), ".resources[0].metadata.engine") == "redis" AND jq(aws.details(), ".resources[0].metadata.engineVersion | split(\".\")[0] | tonumber") >= 7) > OR > (jq(aws.details(), ".resources[0].metadata.engine") == "memcached" AND jq(aws.details(), ".resources[0].metadata.engineVersion | split(\".\")[0] | tonumber") >= 1 AND jq(aws.details(), ".resources[0].metadata.engineVersion | split(\".\")[1] | tonumber") >= 6) > failureMessage: null > filter: > category: RESOURCE > query: entity_descriptor.info.`x-cortex-type` = "elasticache" > level: null > title: Elasticache EOL Version Upgrade Completed > weight: 10 > tag: aws-end-of-life-migration > filter: > category: RESOURCE > query: entity_descriptor.info.`x-cortex-type` = "rds" OR > entity_descriptor.info.`x-cortex-type` = "lambda" OR > entity_descriptor.info.`x-cortex-type` = "elasticache" > ``` ## Create AWS EOL Scorecard in the Cortex UI ### Step 1: Create the Scorecard and configure its basic details 1. In Cortex, navigate to **Scorecards** and click **+Create Scorecard**. Start with a blank Scorecard. 2. Configure the basic details. * Include a name that helps your users understand the purpose of the Scorecard (e.g., `Upcoming EOL for AWS`) and a description. 3. Under "Apply to specific entities," narrow the scope of your Scorecard by choosing `RDS`, `Lamba`, and `AWS Elasticache for Redis` entity types.\ ![](https://mintcdn.com/cortex-290c0c42/qRY2zZcIyXqFVeCq/guides/images/migration-scorecard-entity-types.jpg?fit=max\&auto=format\&n=qRY2zZcIyXqFVeCq\&q=85\&s=37d99758a1523e3f47f68889413d6f95) ### Step 2: Add levels and rules 1. Under **Define evaluation rules**, add two levels: * EOL Upgrade Required * No Pending EOL Upgrade 2. In the "No Pending EOL Upgrade" level, add a rule called `PostgreSQL EOL Version Upgrade Completed`. Include a CQL expression that verifies the entities are not on EOL versions. The following rule passes when Aurora PostgreSQL is 13.x or when Aurora MySQL is 8.x: ``` (jq(aws.details(), ".resources[0].engine") == "aurora-postgresql" AND jq(aws.details(), ".resources[0].engineVersion | startswith(\"13.\")") == true) OR (jq(aws.details(), ".resources[0].engine") == "aurora-mysql" AND jq(aws.details(), ".resources[0].engineVersion | startswith(\"8.\")") == true) ``` 3. Add another rule called `Elasticache EOL Version Upgrade Completed`. Include a CQL expression that verifies the entities are not on EOL versions. The following rule passes when Redis is 7.x or newer, Memcached is 1.6 or newer, or if no Elasticache exists for the entity: ``` (jq(aws.details(), ".resources[0].metadata.engine") == "redis" AND jq(aws.details(), ".resources[0].metadata.engineVersion | split(\".\")[0] | tonumber") >= 7) OR (jq(aws.details(), ".resources[0].metadata.engine") == "memcached" AND jq(aws.details(), ".resources[0].metadata.engineVersion | split(\".\")[0] | tonumber") >= 1 AND jq(aws.details(), ".resources[0].metadata.engineVersion | split(\".\")[1] | tonumber") >= 6) ``` 4. At the bottom of the page, click **Save Scorecard**. # Validate data after migration Source: https://docs.cortex.io/guides/migrations-and-modernization/validate-data [Data verifications](/configure/settings/entity-settings/verification) ensure that entity data in the catalog (e.g., ownership and metadata) stays accurate over time. As a best practice after migrating data (for example, migrating services from spreadsheets into Cortex), we recommend scheduling a data verification to ensure your entities are up to date. ## Set up a data verification after a migration You must have the `Configure verification periods` permission to set up a verification. 1. In Cortex, navigate to the [Entity verification settings](https://app.getcortexapp.com/admin/settings/entities/verification) page. Click **+Add verification period**. 2. In the side panel, fill in the fields: * **Start date** and **End date**: Enter the start and end dates for the verification period. * The start date cannot be in the past. The end date must be at least one day after the start date. * Choose a timeframe that is reasonable based on the number of entities that each team will need to verify. * **Name**: Enter a descriptive name, e.g., `Validate data after migration`. * **Verification instructions**: Enter clear and concise instructions that will appear on the entity's details page, e.g., `These entities were recently imported from spreadsheets. Please review and verify whether they're accurate.` * **Require reason for verification**: Check this box to require the user to include a reason if they confirm that the entity's data is invalid. * We recommend requiring a reason, as it will allow you to quickly understand what needs to be fixed on an entity. * **Team member roles responsible for verification**: Select which Cortex users will be responsible for verifying data. * If you select multiple roles, any of those users can verify data. * If you do not select a team member role, any user who owns the entity can verify data. * **Entities to verify**: Specify which entities the verification policy applies to. * You can select a specific entity type to include (for example, you could apply the verification to all entities of the type `service`) or if your entities have groups assigned, you can filter by specific groups. * Under **Advanced options**, you can use CQL to refine which entities you want to verify. For example, you might narrow your selection to entities created in the last two weeks:\ `entity.created() < duration("P2W")` 3. Click **Create verification period**. Within a few minutes of saving the verification period, it will be visible to admins in the list of verifications on the [Entity verification settings page](https://app.getcortexapp.com/admin/settings/entities/verification). Entity owners will receive notifications to verify their entities. ## Remediate entities with incorrect data After setting up the verification period, you can [create a CQL report to view all entities that have been verified as incorrect](/configure/settings/entity-settings/verification#view-all-unverified-or-incorrect-entities) using a prebuilt CQL report template. Cortex also offers a prebuilt [Scorecard template to flag entities that have not yet been verified](/configure/settings/entity-settings/verification#flag-unverified-entities-via-scorecard). # Automate a sync in ArgoCD Source: https://docs.cortex.io/guides/operational-readiness/argocd-workflow After integrating Cortex with [ArgoCD](/ingesting-data-into-cortex/integrations/argocd), you can use [Workflows](/streamline/workflows) to streamline and automate daily tasks. Rather than manually performing a sync through the ArgoCD UI, you can automate syncs by leveraging the ArgoCD API in a Workflow. This guide walks through a Workflow that will sync the ArgoCD application to the same cluster that ArgoCD is running, but to a different namespace, and will allow the user to choose options for the sync. ## How to automate an ArgoCD sync with a Workflow in Cortex ### Prerequisites Before getting started: * Create an [API token in ArgoCD](https://argo-cd.readthedocs.io/en/stable/). * In ArgoCD, navigate to your account settings then click **Tokens > Generate New**. Copy the token and store it in a secure location, as you will need it in the next steps.\ ![argocd actions 1](https://mintcdn.com/cortex-290c0c42/qRY2zZcIyXqFVeCq/guides/images/argocd-actions-1.jpeg?fit=max\&auto=format\&n=qRY2zZcIyXqFVeCq\&q=85\&s=90662d71050588b23eb9d58865d6341d) * Create a secret in Cortex. * Give the secret the name `argocd`. * For the secret value, enter the value of your ArgoCD API token. ### Step 1: Create a Workflow 1. In the main nav of Cortex, click **Workflows**. 2. Follow the steps of the [Workflows documentation](/streamline/workflows/create) to start creating a Workflow from scratch and configure its settings. * Give the Workflow a descriptive name such as "Create and sync application." * In the **Response template** field you can pass a blank response body or use [Mustache templating](https://mustache.github.io/) to create messages depending on what the user enters in each field. * For example, you may want to configure a response to confirm whether a sync was successful when the workflow is run. You could add the following to check the `sync.status` field. This example assumes you add an HTTP request action with the slug `http-request` in your Workflow: ``` {{#actions.http-request.outputs.body.status.sync.status}} Successfully synced application! {{/actions.http-request.outputs.body.status.sync.status}} {{^actions.http-request.outputs.body.status.sync.status}} Unable to sync application. Are you sure this application exists in ArgoCD? {{/actions.http-request.outputs.body.status.sync.status}} ``` ### Step 2: Add blocks to the Workflow In your Workflow, you will add an HTTP request block to call the ArgoCD sync via the [ArgoCD API](https://argoproj.github.io/argo-events/sensors/triggers/http-trigger/), and a user input block where you define inputs that map to the JSON body of the block. The inputs should be the same sync options shown under **Sync** in your ArgoCD instance. The instructions below map `REVISION`, `DRY RUN`, and `PRUNE` as the sync options. See the [Workflows documentation](/streamline/workflows/blocks) for more information on configuring blocks. 1. In the Workflow, click **+** to add a block. Select **User input**. Configure the block: * **Block name**: Enter a name for the block (e.g., `User input`). * **Slug**: The slug field is automatically populated based on the block name. * Under "User input fields," click **Add input**. Configure the input: * **Type**: Select `Text`. * **Name**: Enter `Revision`. * **Placeholder**: Enter `HEAD`. * At the bottom of the modal, click **Add input field**. * Under "User input fields," click **Add input**. Configure another input: * **Type**: Select `Toggle`. * **Name**: Enter `Dry run`. * At the bottom of the modal, click **Add input field**. * Under "User input fields," click **Add input**. Configure another input: * **Type**: Select `Toggle`. * **Name**: Enter `Prune`. * At the bottom of the modal, click **Add input field**. 2. Click **Save**. 3. In the Workflow, click **+** to add another block. Select **HTTP request**. Configure the block: * **Block name**: Enter a name for the block (e.g., `HTTP request`). * **Slug**: The slug field is automatically populated based on the block name. * **HTTP method**: Select `POST`. * **URL**: Enter the target URL. * **Headers**: Enter the following key/value pairs: * **Header Key**: `Authorization`, **Header Value**: `Bearer {{{context.secrets.argocd}}}` * If you used a different name for your secret, replace `argocd` with your secret's name. * **Payload**: Enter the payload referencing the output of the "User input" block. The payload that you supply can be templated and can reference an entity that the Workflow is being run with. * In this example, you could enter: ```json theme={null} { "prune": {{context.actions.user-input.outputs.prune}}, "dryRun": {{context.actions.user-input.outputs.dry-run}}, "revision": "{{context.actions.user-input.outputs.revision}}" } ``` 4. Click **Save**. 5. Click **Save Workflow**. # Run a Humanitec pipeline Source: https://docs.cortex.io/guides/operational-readiness/humanitec-pipeline [Humanitec](https://humanitec.com/) offers products to build on top of your Internal Developer Portal (IDP) for containerized workloads. You can use a Workflow in Cortex to call the Humanitec API and run a Humanitec pipeline. For instructions, see [Integrations > Humanitec](/ingesting-data-into-cortex/integrations/humanitec). # Call internal service endpoints in a Workflow Source: https://docs.cortex.io/guides/operational-readiness/internal-endpoints Your organization may have services that are not publicly accessible but contain information that would be useful to manage in Cortex. You can use an [HTTP action in a Workflow](/streamline/workflows/create) and [Cortex's Axon Relay](/ingesting-data-into-cortex/integrations/axon-relay) to call internal services without exposing the service or authentication outside of your firewall. ### How to call internal service endpoints in a Workflow [#how-to-call-internal-service-endpoints-in-a-workflow](#how-to-call-internal-service-endpoints-in-a-workflow) #### Prerequisites [#prerequisites](#prerequisites) Before getting started, you should have already [set up the Cortex Axon agent](/ingesting-data-into-cortex/integrations/axon-relay) and [set your Cortex API token in the .env file](/ingesting-data-into-cortex/integrations/axon-relay#step-1-2-create-a-env-file-and-a-docker-compose-yml-file). **Considerations** * This guide describes using a Docker compose file, but note that Axon Relay can be run in Kuberenetes or other container systems. * As an example throughout this guide, assume a service in the network has the following endpoint: `GET http://cities.internal.my-company.com/api/cities/s => ["Seattle", "Sydney", "Shanghai" ...]` #### Step 1: Create request forwarding configuration [#step-1-create-request-forwarding-configuration](#step-1-create-request-forwarding-configuration) * Create a file that defines how requests are routed. * The example below permits any requests, but note that the `method` and `path` can be narrowed to allow access to specific endpoints: ``` { "private": [ { "method": "any", "path": "/*", "origin": "http://cities.internal.my-company.com" } ] } ``` #### Step 2: Configure Axon Docker container [#step-2-configure-axon-docker-container](#step-2-configure-axon-docker-container) 1. Create an accept file (in this example, `docker-compose.yml`) that defines how the container will route traffic and which routes are allowed. * For production employments, two replicas should be specified. The example below can be used to test the system. ``` services: relay-cities: image: ghcr.io/cortexapps/cortex-axon-agent:latest environment: HOSTNAME: relay-cities-${HOSTNAME:-local} CORTEX_API_TOKEN: $CORTEX_API_TOKEN volumes: - "./accept.cities.json:/app/accept.json" command: [ "relay", "-a", "axon-relay-cities", # this can be any unique value "-f", "/app/accept.json", ] ``` 2. Start the container, which will register it with Cortex: Run the command `docker compose up`. #### Step 3: Create the Workflow in Cortex [#step-3-create-the-workflow-in-cortex](#step-3-create-the-workflow-in-cortex) 1. Follow the [steps to start creating a Workflow](/streamline/workflows/create#creating-a-workflow) and [configure its basic details](/streamline/workflows/create#creating-a-workflow). 2. Add an HTTP request block to your Workflow. Configure the block: * **Block name**: Enter a human readable name. * **Slug**: Enter a unique identifier for the block. * **HTTP method**: GET * **URL**: Enter a URL in the following format: `http://[your-configuration-alias]@relay-proxy.cortex.io[/desired/url/path]` * For the example from this guide, it would be `http://axon-relay-cities@relay-proxy.cortex.io/api/cities/s` * **Headers**: For more information on headers, see the [HTTP request block documentation](/streamline/workflows/create). 3. After saving your changes, run the Workflow. * Click **Run** at the top of the Workflow. * Learn more about Workflow runs in [Running a Workflow](/streamline/workflows/run). After running the Workflow, check its **Outputs** for the "Call cities endpoint" data: ![The 'call cities endpoint' data appears in the Output of the Workflow.](https://mintcdn.com/cortex-290c0c42/qRY2zZcIyXqFVeCq/guides/images/cities-endpoint.jpg?fit=max\&auto=format\&n=qRY2zZcIyXqFVeCq\&q=85\&s=efea92adc630a9eb7d95ddb98241049d) # Loop in a JavaScript block and return specified output Source: https://docs.cortex.io/guides/operational-readiness/javascript-looping The [JavaScript block](/streamline/workflows/blocks#configuring-a-core-block) in a Cortex Workflow allows you to write custom scripts directly in your Workflow logic, giving you the flexibility to streamline tasks that would otherwise require additional tooling or manual intervention. Common use cases include: * Transforming data: Use JavaScript to convert API responses or output from another block into something easier to use downstream. * Filtering or searching inside data: Narrow down results from a previous block, like selecting high-priority items or matching a tag. * Math and aggregation: Run calculations across arrays or values, including handling time-based logic. * Defaults and fallbacks: Avoid runtime errors by checking if values exist before using them elsewhere in the Workflow. ## Configure a JavaScript block to return user names and company names The example below demonstrates how to fetch and work with example user data from a public API. In this example, you call an external API, parse and loop through the results, then return useful output into the [Workflow's evolving state](/streamline/workflows/blocks/states). It performs the following actions: 1. Sends a GET request to `jsonplaceholder.typicode.com/users` 2. Sets a typical `Content-Type` header 3. Uses `await` to pause execution until the response is received 4. Turns the data into an array of objects and creates a flat array of strings 5. Once the response is received, it parses the JSON body and extracts just the user names and their company names The final output includes the HTTP status code and a simplified list of users. This output becomes part of the `actions` object. Both the `responseStatus` and the parsed `users` array are now available as action context, which can be [referenced in subsequent steps of the Workflow](/guides/operational-readiness/javascript-looping#referencing-the-output-later-in-the-workflow). #### Alternate option: Upload the example Workflow YAML The instructions on this page describe how to create this Workflow in the Cortex UI, but it is also possible to copy the Workflow YAML and add it to your workspace via the [Cortex CLI](https://pypi.org/project/cortexapps-cli/). This allows you to quickly set up the example configuration then iterate on it for your own use case. Expand the tile below to learn more. > **Create the Workflow via Cortex CLI** > > To upload the Workflow example YAML into your workspace: > > 1. Save the JavaScript Workflow example YAML file below: > > ```yaml theme={null} > name: JS Block Example Workflow > tag: workflow-tag > description: This is an example demonstrating how to use looping in a JavaScript block. > isDraft: true > filter: > type: GLOBAL > runResponseTemplate: null > failedRunResponseTemplate: null > actions: > - name: JavaScript > slug: javascript > schema: > script: "// Example base URL \nconst baseUrl = `https://jsonplaceholder.typicode.com/users`;\ > \ // Public API that returns fake user data\n\nconst myHeaders = {\n \"\ > Content-Type\": \"application/json\" // Typical header for JSON APIs \n};\n\ > \n// Send the HTTP request and wait for the response to come back\nconst response\ > \ = await fetch(baseUrl, {\n headers: myHeaders // Makes a GET request with\ > \ the specified headers\n});\n// Pauses the function until the fetch call finishes\ > \ (asynchronously)\n\n// Parse the response body as JSON and wait for it to\ > \ complete\nconst responseBody = await response.json(); \n\n// Create a simplified\ > \ array of objects with name and company\nconst simplifiedUsers = responseBody.map(user\ > \ => ({\n name: user.name, // Pulls out the user's full name\n\ > \ company: user.company.name // Pulls out the name of the user's company\n\ > }));\n\n// Create a flat array of strings like \"Leanne Graham (Romaguera-Crona)\"\ > \n// This is required for use in dropdowns or multiselect inputs\nconst usersFormatted\ > \ = simplifiedUsers.map(user => `${user.name} (${user.company})`);\n\nreturn\ > \ {\n responseStatus: response.status, // Returns the HTTP status code (e.g.,\ > \ 200 for success)\n users: simplifiedUsers, // Cleaned-up list\ > \ of name + company pairs (objects)\n usersFormatted: usersFormatted //\ > \ Flat string array — works in User Input blocks\n};\n" > type: JAVASCRIPT > outgoingActions: > - user-input > isRootAction: true > - name: User input > slug: user-input > schema: > inputs: > - name: Choose name > description: In this step, select a name from the dropdown > key: choose-name > required: false > options: [] > defaultValue: null > placeholder: null > allowAdditionalOptions: false > type: SELECT_FIELD > inputOverrides: > - inputKey: choose-name > outputVariable: actions.javascript.outputs.result.usersFormatted > type: OPTION > type: USER_INPUT > outgoingActions: [] > isRootAction: false > runRestrictionPolicies: [] > iconTag: null > ``` > > 2. Use the [Cortex CLI](https://pypi.org/project/cortexapps-cli/) to run this command, using the path to your Workflow YAML file:\\ > > `cortex workflows create -f ` ### Add a JavaScript block to the Workflow 1. Follow the instructions to [create a Workflow](/streamline/workflows/create) and [configure its settings](/streamline/workflows/create#creating-a-workflow). 2. Add a JavaScript block to your Workflow. * In the block configuration side panel, add a block name and a unique slug. 3. Under the **Javascript** header, in the text editor, enter your JavaScript expression.\ ![The JavaScript text editor appears under the Block name and Slug fields.](https://mintcdn.com/cortex-290c0c42/qRY2zZcIyXqFVeCq/guides/images/js-block-editor.jpg?fit=max\&auto=format\&n=qRY2zZcIyXqFVeCq\&q=85\&s=80bad4432cc4feeceeb368c1f2cbeae5) In this example, we use the following: ```javascript theme={null} // Example base URL const baseUrl = `https://jsonplaceholder.typicode.com/users`; // Public API that returns fake user data const myHeaders = { "Content-Type": "application/json" // Typical header for JSON APIs }; // Send the HTTP request and wait for the response to come back const response = await fetch(baseUrl, { headers: myHeaders // Makes a GET request with the specified headers }); // Pauses the function until the fetch call finishes (asynchronously) // Parse the response body as JSON and wait for it to complete const responseBody = await response.json(); // Create a simplified array of objects with name and company const simplifiedUsers = responseBody.map(user => ({ name: user.name, // Pulls out the user's full name company: user.company.name // Pulls out the name of the user's company })); // Create a flat array of strings like "Leanne Graham (Romaguera-Crona)" // This is required for use in dropdowns or multiselect inputs const usersFormatted = simplifiedUsers.map(user => `${user.name} (${user.company})`); return { responseStatus: response.status, // Returns the HTTP status code (e.g., 200 for success) users: simplifiedUsers, // Cleaned-up list of name + company pairs (objects) usersFormatted: usersFormatted // Flat string array — works in User Input blocks }; ``` 4. Click **Save** at the bottom of the block configuration side panel. ### Run the Workflow * After you have finished creating your Workflow, click **Run** in the upper right corner while viewing the Workflow.\ After the run completes, go to the **Outputs** tab of the run to view the `users` and `responseStatus` values returned by the JavaScript block: ![The run output includes the user names and companies.](https://mintcdn.com/cortex-290c0c42/qRY2zZcIyXqFVeCq/guides/images/workflow-js-output.jpg?fit=max\&auto=format\&n=qRY2zZcIyXqFVeCq\&q=85\&s=a96b27dff841279e32cf1bec23ca6483) ## Referencing the output later in the Workflow It is possible to reference the outputs of the JavaScript block later in the Workflow, using the following: * `actions..outputs.result.usersFormatted` * `actions..outputs.result.responseStatus` ### Example: Add a User input block after the JavaScript block You might later want to include a **User input** block where the person running the Workflow can select a name from the JavaScript block's output: 1. In your Workflow, add a **User input** block. 2. In the block configuration side panel, include a name and a unique slug for the block, then click **Add user input**. 3. Configure the input: * Enter a name and key for the input. * In this example, the name is "Choose name." * Select a type. This example uses the `Select` type. * In the **Path to override value** field, include a reference to the list of `users` that came from the output of the JavaScript block (which uses the slug `javascript`):\ `actions.javascript.outputs.result.usersFormatted` 4. Click **Save** at the bottom of the block configuration side panel. 5. Run the Workflow. 6. After the JavaScript block runs, you will be prompted to select a name. After selecting, click **Submit**.\ ![During a user input step, select an option from the dropdown.](https://mintcdn.com/cortex-290c0c42/qRY2zZcIyXqFVeCq/guides/images/provide-user-input-block.jpg?fit=max\&auto=format\&n=qRY2zZcIyXqFVeCq\&q=85\&s=9ff6f8dae493f90e3ac0a13cb8b2b035) After you run the Workflow and select a choice, you will see the choice in the **Outputs** tab at the bottom of the page: ![The object you chose during the User Input step will appear in the Outputs tab of the workflow run.](https://mintcdn.com/cortex-290c0c42/qRY2zZcIyXqFVeCq/guides/images/user-input-outputs-block.jpg?fit=max\&auto=format\&n=qRY2zZcIyXqFVeCq\&q=85\&s=3ebd47b6948c4e4544343e7d20f6a615) #### Next steps After a user makes a select from your User input block, you can use the collected input in many different ways in the next steps of your Workflow. For example: * **Branch the Workflow based on the user's selection**: You could add a [Branch block](/streamline/workflows/blocks#configuring-a-core-block). This can use a conditional expression (in CEL syntax) that references the user's selection to determine the path the Workflow should take next. * For example, you might set a path expression like `actions["user-input"].outputs.selection == "Leanne Graham (Romaguera-Crona)"` to run a specific set of steps if the user chose the name `Leanne Graham (Romaguera-Crona)` from the dropdown during the User input step. * **Trigger integration blocks**: The user's selection could be used to [drive actions in third-party integrations](/streamline/workflows/blocks#configuring-an-integration-block) such as creating a Pull Request in GitHub, sending a notification to Slack or Microsoft Teams, and more. Cortex offers a [block library](/streamline/workflows/blocks#configuring-a-workflow-block-basic) with over 200 actions to choose from. # Trigger internal Jenkins jobs Source: https://docs.cortex.io/guides/operational-readiness/jenkins-axon You can use [Cortex Workflows](/streamline/workflows) and [Axon Relay](/ingesting-data-into-cortex/integrations/axon-relay) to trigger Jenkins jobs running inside your private network without exposing your CI/CD tools to the public internet. This guide walks you through setting up a Docker-based Jenkins instance, configuring Axon Relay to communicate with it securely, and building a Workflow that listens for the job result via callback URL. ### Prerequisites Before getting started: * Create a [Cortex API token](/configure/settings/api-keys). * You should have the following tools installed locally: * [Docker](https://docs.docker.com/get-docker/) * [Docker Compose](https://docs.docker.com/compose/install/) * You should have [Jenkins](https://hub.docker.com/r/jenkins/jenkins) configured (used via Docker container in this guide). ### **Considerations** * This guide describes using a Docker compose file, but note that Axon Relay can be run in Kubernetes or other container systems. ### Step 1: Configure Jenkins 1. Start a basic Jenkins instance in Docker: ```bash theme={null} docker run -p 9090:8080 -p 50000:50000 jenkins/jenkins:lts ``` 2. Once Jenkins starts, follow the UI to unlock and configure it. [Create a new job](https://www.jenkins.io/doc/book/pipeline/getting-started/#through-the-classic-ui), and use the following example simple pipeline: > [!NOTE] > > This script includes a `Hello World` stage for lightweight setup and testing. Replace it with your own build, test, or deployment logic. ``` pipeline { agent any parameters { string( name: 'callbackURL', defaultValue: '', description: 'The callback URL to POST to' ) } stages { stage('Hello World') { steps { echo 'Hello World' } } } post { always { script { if (params.callbackURL?.trim()) { def status = currentBuild.currentResult ?: 'SUCCESS' def message = "" def statusCode = "" if (status == 'SUCCESS') { message = "Pipeline completed successfully" statusCode = "success" } else { message = "Pipeline failed during execution" statusCode = "failure" } withCredentials([string(credentialsId: 'cortex_api_token', variable: 'API_TOKEN')]) { sh """ curl -X POST "${params.callbackURL}"\ -H "Content-Type: application/json" \ -H "Authorization: Bearer \${API_TOKEN}" \ -d '{ "status": "update", "message": "${message}", "response": { "build_number": "${env.BUILD_NUMBER}", "job_name": "${env.JOB_NAME}", "timestamp": "'"\$(date -Iseconds)"'"} }' \ --fail \ --show-error curl -X POST "${params.callbackURL}"\ -H "Content-Type: application/json" \ -H "Authorization: Bearer \${API_TOKEN}" \ -d '{ "status": "${statusCode}", "message": "${message}" }' \ --fail \ --show-error """ } echo "Sent ${statusCode} notification to ${params.callbackURL}" } else { echo "No callback URL provided, skipping POST request" } } } failure { echo "Pipeline failed!" } success { echo "Pipeline completed successfully!" } } } ``` ### Step 2: Set up and run Axon Relay To call a Jenkins instance behind a firewall, you’ll need to run the [Cortex Axon Relay](/ingesting-data-into-cortex/integrations/axon-relay) locally or within your infrastructure. #### **Step 2.1: Create the `.env` file** In your project directory, create a file called `.env`. It should include: ```env theme={null} CORTEX_API_TOKEN= JENKINS_URL= JENKINS_TOKEN= ``` Make sure these environment variables match the configuration of your Jenkins instance. > [!NOTE] > > If Jenkins and Axon are running on the same machine, Axon Relay may have issues reaching Jenkins using `http://localhost` or `127.0.0.1`, since those addresses refer to the container’s internal network. > > A workaround is to use a tunneling service like [ngrok](https://ngrok.com/) to expose Jenkins with a public HTTPS URL. If you do so, use the generated public HTTPS URL as the value for `JENKINS_URL`. #### **Step 2.2: Create `accept.json`** In your project directory, create a file called `accept.json`, which controls what endpoints the Relay is allowed to forward requests to: ``` { "private": [ { "method": "any", "path": "/*", "origin": "${JENKINS_URL}", "auth": { "scheme": "basic", "value": "${JENKINS_TOKEN}" } } ] } ``` #### **Step 2.3: Create `docker-compose.yml`** The `docker-compose.yml` file defines how to run the Cortex Axon agent (Relay) using Docker Compose. This file tells Docker how to configure and launch the Relay service so it can securely connect to your internal Jenkins instance and communicate with Cortex. In your project directory, create the following file: ```yaml theme={null} services: jenkins-relay: image: ghcr.io/cortexapps/cortex-axon-agent:latest env_file: .env volumes: - "./accept.json:/app/accept.json:rw" command: [ "relay", "-a", "jenkins-relay", # This must match the alias used in the Workflow block "-f", "/app/accept.json" ] ``` #### **Step 2.4: Run Axon Relay** From your terminal, run: ```bash theme={null} docker compose up ``` Axon Relay will start and register with Cortex using your API token. ### Step 3: Create the Workflow in Cortex 1. Follow the steps to [start creating a Workflow](/streamline/workflows/create) and [configure its basic details](/streamline/workflows/create#creating-a-workflow). 2. Add an [**Async HTTP request**](/streamline/workflows/blocks#configuring-a-core-block) block to your Workflow. Configure the block: * **Block name**: Enter a descriptive name, e.g., `Trigger Jenkins job`. * **Slug**: Enter a unique identifier for the block. * **HTTP method**: `POST` * **URL**: Enter the relay URL for your Jenkins job, in the following format:\ `https://.relays.cortex.io/job//buildWithParameters?callbackURL={{callbackUrl}}` * Replace `` with the alias you assigned to the Relay in your `docker-compose.yml` file (e.g., `jenkins-relay`). * Replace `` with the name of the job you want to trigger in Jenkins. * `{{callbackUrl}}` is a dynamic value provided by Cortex and required for async blocks. 3. Save the block. 4. In the upper right corner of the page, click **Save Workflow**. ![](https://mintcdn.com/cortex-290c0c42/qRY2zZcIyXqFVeCq/guides/images/zight-2025-08-14-at-5-00-11-pm.jpg?fit=max\&auto=format\&n=qRY2zZcIyXqFVeCq\&q=85\&s=3f5f0faee181abb7774d78dc6504c369) ### Step 4: Run the Workflow * Click **Run** on your Workflow. > [!TIP] > > Learn more about Workflow runs in [Running a Workflow](/streamline/workflows/run). When you run the Workflow, the following actions happen: 1. Cortex will POST to Jenkins via Axon. 2. Jenkins starts the job and makes two POSTs back to Cortex: * One `update` while in progress. * One `success` or `failure` when done. 3. The Workflow resumes and displays output in the **Async HTTP** block results: * Metadata about the initial outbound request to Jenkins (e.g., status, headers) * A callback with the job name, build number, and timestamp * A final result with success or failure ![](https://mintcdn.com/cortex-290c0c42/qRY2zZcIyXqFVeCq/guides/images/zight-2025-08-14-at-9-07-47-pm.jpg?fit=max\&auto=format\&n=qRY2zZcIyXqFVeCq\&q=85\&s=e9ee77464c05bf9dd630a46199d2d5c5) # Kick off a Jenkins pipeline Source: https://docs.cortex.io/guides/operational-readiness/jenkins-workflow After integrating Cortex with [Jenkins](/ingesting-data-into-cortex/integrations/jenkins), you can use a Cortex [Workflow](/streamline/workflows) to kick off your pipeline directly through Cortex, rather than switching to Jenkins to launch a build. For full instructions on creating and configuring Workflows, see the [Workflows documentation](/streamline/workflows). ## How to kick off a Jenkins pipeline in a Workflow ### Prerequisites Before getting started: * [Configure your Jenkins instance in Cortex](/ingesting-data-into-cortex/integrations/jenkins#step-3-configure-jenkins-in-cortex-to-enable-jenkins-workflow-blocks). ### Step 1: Create a workflow 1. In the main nav of Cortex, click **Workflows**. 2. Follow the steps of the [Workflows documentation](/streamline/workflows) to start creating a Workflow from scratch and configure its settings. * Give the Workflow a descriptive name such as "Kick off Jenkins pipeline." ### Step 2: Add blocks to the workflow You can add a block to run a build with parameters, or you can add a block to run a build without parameters. See the Jenkins documentation for [more information on submitting parameterized jobs](https://wiki.jenkins.io/display/JENKINS/Parameterized+Build). 1. Click **+** to view the block library. 2. Click **Jenkins**. * To choose a a build without parameters, select **Run a build**. * To choose a build with parameters, select **Run a build with parameters**. 3. Click **Insert** at the bottom of the library.\ ![Select the Jenkins 'Run a build' block.](https://mintcdn.com/cortex-290c0c42/qRY2zZcIyXqFVeCq/guides/images/jenkins-block.jpg?fit=max\&auto=format\&n=qRY2zZcIyXqFVeCq\&q=85\&s=9e7ddf446a95be5fec94770b64bbf2d2) 4. In the side panel, configure the block. * **Block name**: Enter a name for the block (e.g., `Run a build in Jenkins`). * **Slug**: Enter a unique slug for the block. * **Alias**: Select the alias of your Jenkins instance. * **Job name**: Enter the name of the Jenkins job to run. * **Parameters**: For a build with parameters, you also need to configure valid JSON for the run job parameters. 5. At the bottom of the side panel, click **Save**. # Tracking cloud costs Source: https://docs.cortex.io/guides/operational-readiness/tracking-cloud-costs Bring cloud spend into Cortex so infrastructure cost lives alongside the rest of your engineering health data (deployment frequency, reliability, scorecard compliance) instead of sitting in a separate FinOps tool that engineers never open. This guide walks through surfacing actuals, budgets, and forecasts at the team level, displaying them on entity pages, and wiring cost into your scorecards. By the end, your engineering managers will be able to answer, ***How much is my team spending, and are we on track against budget?***, without leaving Cortex. ![A custom 'Cloud cost' dashboard in Cortex.](https://mintcdn.com/cortex-290c0c42/qRY2zZcIyXqFVeCq/guides/images/screenshot-2026-06-10-at-2-25-38-pm.png?fit=max\&auto=format\&n=qRY2zZcIyXqFVeCq\&q=85\&s=89a16f8ef10db02fcec2930287968c4c) ## Prerequisites 1. The `Configure Eng Intelligence custom metrics` permission to create and publish metric definitions. 2. An [API key](/configure/settings/api-keys#creating-an-api-key-in-cortex) with the same permission if you plan to push data programmatically (most cloud cost setups do). 3. Cost data you can export on a schedule from your cost management platform (AWS Cost Explorer, Azure Cost Management, Databricks, New Relic, etc.), or a CQL-computable source already in Cortex. ### **Custom metrics or custom data?** Use [custom metrics](/guides/operational-readiness/tracking-cloud-costs#step-2-creating-custom-metrics) for anything that changes over time, e.g. monthly spend, budget targets, and forecasts. Cost dollars are a time series, so they belong in custom metrics. See [Custom metrics](/improve/eng-intelligence/custom-metrics) to learn more. Use [custom data](/guides/operational-readiness/tracking-cloud-costs#step-5-tagging-entities-for-cost-attribution-custom-data) for slowly-changing tags like a cost-center or cost-attribution override. Refer to [Custom data](/ingesting-data-into-cortex/entities-overview/entities/custom-data) for more information. ## Step 1: Modeling your cost metrics Cloud cost is most actionable at the team level where a budget owner can actually do something about it. Attach your metrics to team-type entities rather than individual services, at least to start. A complete picture has three dimensions. A typical setup uses one metric per provider, per dimension: **Actuals** *(what was spent)*: * Total cloud cost * AWS cost * Azure cost * Databricks cost * New Relic cost * AWS Marketplace cost **Budgets** *(planned spend targets)*: * Budgeted AWS * Budgeted Databricks * Budgeted New Relic **Forecasts** *(projected spend for the period)*: * Forecast AWS * Forecast Databricks * Forecast New Relic You don't need every provider in every dimension. It's common for actuals to flow for more teams than budgets and forecasts, since budget planning is usually formalized for a smaller subset. Start with actuals everywhere, then layer in budgets and forecasts where the planning data exists. ![](https://mintcdn.com/cortex-290c0c42/qRY2zZcIyXqFVeCq/guides/images/image.png?fit=max\&auto=format\&n=qRY2zZcIyXqFVeCq\&q=85\&s=2fef34324cb42479d9682f9b1976d37b) ## Step 2: Creating custom metrics Add custom metrics in Cortex via [CQL](/improve/eng-intelligence/custom-metrics#creating-a-custom-metric-via-cql) or [API](/improve/eng-intelligence/custom-metrics#creating-a-custom-metric-via-api). Refer to the table below for field definitions. | Field | Definition | | - | - | | **Ingestion method** | Choose API for cost data exported from an external platform (the common case), or CQL if the underlying numbers already exist in Cortex. If you choose CQL, Cortex evaluates the expression every 12 hours and the result must resolve to a number, or it fails validation. | | **Name** | The name of the custom metric. This is how it appears in Eng Intelligence, e.g. `AWS Cost`. | | **Key** | A unique identifier of letters, digits, and hyphens, e.g. `aws-cost`. **Tip**: Keep a consistent prefix scheme like `cost-actual-aws`, `cost-budget-aws`, `cost-forecast-aws` so the three dimensions group cleanly later. | | **Trend color indicator** | Determine if an upward or downward trend is positive. | | **Draft** | Toggle off once you've validated the data, to make it visible to everyone with Eng Intelligence access. | ![](https://mintcdn.com/cortex-290c0c42/qRY2zZcIyXqFVeCq/guides/images/image-1.png?fit=max\&auto=format\&n=qRY2zZcIyXqFVeCq\&q=85\&s=8b12f6eee60d6ee4cc3d053595f282a7) ## Step 3: Pushing your cost data For externally-sourced cost data, post to each metric via the API on a regular cadence (a daily or monthly job, depending on how often your platform closes the books). * Add points to a single entity, or bulk-add multiple points using `createBulkCustomMetricData` to load many teams at once. * You can backfill up to two years, so load historical spend on first setup to get trends immediately rather than waiting months for them to accumulate. * All API requests need an `Authorization: Bearer ` header. A few operational notes: * Cortex lags custom metric results until the end of the previous day, so today's posted data won't render until tomorrow. * Bulk metric creation via the API is rate-limited. If you're loading dozens of teams, batch your requests and handle `429` responses with a retry-after delay rather than hammering the endpoint. * Custom metric data is retained for 24 months. ## Step 4: Surfacing cost on team pages with a plugin Eng Intelligence and [Data Explorer](/improve/eng-intelligence/data-explorer) show your cost metrics out of the box, but a dedicated custom plugin gives budget owners a purpose-built view on their team page. Build a plugin that displays: * Cloud cost trends across providers * Budget vs. actuals comparison * A unified spend view across AWS, Azure, Databricks, and New Relic Scope the plugin to team-type entities only, so it appears where cost is actionable and stays off individual service pages where it would just be noise. The plugin reads your metric data through the Cortex API, so it stays in sync with whatever cadence you're posting on. ![](https://mintcdn.com/cortex-290c0c42/qRY2zZcIyXqFVeCq/guides/images/image-2.png?fit=max\&auto=format\&n=qRY2zZcIyXqFVeCq\&q=85\&s=66c3bf11368df282bf3e3453cd8f302c) ## Step 5: Tagging entities for cost attribution (custom data) If you need to attribute or override how individual services and resources roll up to a cost center, use a custom data field rather than a metric (this is the slowly-changing-metadata case). A field like operational-cost-override applied across your catalog lets your cost platform (or your own CQL) map services back to the right team or product. This is what makes accurate chargeback and showback possible: the metrics tell you how much, the custom data tells you whose. ## Step 6: Putting cost to work in Scorecards and reports Once cost is flowing, it stops being a dashboard and starts being a control: * **Scorecard rules** - Flag teams whose actual spend exceeds forecast by more than a threshold, or whose spend has grown month-over-month beyond a set percentage. Cost becomes a standard you can drive, not just a number you observe. See [Scorecard rule filters](/standardize/scorecards/scorecard-filters) * **CQL reports** - Build a tabular, cross-team cost comparison so leadership can rank spend without manually aggregating from a finance export. See [Using CQL reports](/standardize/cql/cql-reports) * **Service-level cost** - Once team-level patterns are solid, extend attribution down to individual services using your cost-attribution custom data, so you can answer, ***Which service is driving this team's bill?*** ![](https://mintcdn.com/cortex-290c0c42/qRY2zZcIyXqFVeCq/guides/images/image-3.png?fit=max\&auto=format\&n=qRY2zZcIyXqFVeCq\&q=85\&s=5335f346ce7e000b148104584a2080dd) ## What you end up with Cost data living where engineering decisions are made—closing the loop between the teams writing the code and the teams accountable for the bill—scoped to the level where someone can act on it, and tied into the same scorecards and reports that govern everything else in your catalog. # Visualizing custom data in a plugin Source: https://docs.cortex.io/guides/operational-readiness/visualizing-custom-data-in-a-plugin Plugins let you build lightweight UI extensions that surface metadata directly in the Cortex UI. Cortex already renders custom data automatically in the **Custom data & metrics tab** on every [entity page](/ingesting-data-into-cortex/entities-overview/entities/details). However, many teams want to go further, like adding richer visualizations, grouping related fields, embedding links, or turning custom data into more opinionated dashboards. This guide shows how to build a plugin page that reads custom data and renders it using your own UI. ### Overview Cortex supports attaching structured metadata to any catalog entity using [**Custom Data**](/ingesting-data-into-cortex/entities-overview/entities/custom-data). This metadata automatically appears in the **Custom Data** tab of the entity page. If your team wants to: * organize fields into custom sections * add tables, charts, or diagrams * highlight important metadata * provide context-specific controls * match a specific visualization or compliance requirement a plugin can fetch the same custom data and render a tailored UI that sits alongside the built-in Cortex experience. ### Step 1: Add custom data to an entity To add custom data to an entity, you can use the [Custom Data API](/api/rest/custom-data/add-custom-data-for-entity). To illustrate how this works, we’ll use the following fictional metadata object: ```json theme={null} { "service_owner": "Payments Team", "languages": "Node.js, TypeScript", "dependencies": "Redis, Kafka, BillingAPI", "service_tier": "Tier 2", "last_reviewed": "2025-11-01", "links": "[https://docs.example.com/runbook, https://example.com/architecture]" } ``` This object is stored under the custom data key `sample-metadata`. ``` sample-metadata ``` ### Step 2: Register the plugin Once you have custom data to visualize, [register your plugin](https://app.getcortexapp.com/admin/plugins/new) in Cortex. Follow the [Creating Plugins documentation](/streamline/plugins/creating-plugins), making sure to choose `Specific entity types` as the context. This ensures your visualization displays when viewing an entity that contains the custom data. ![](https://mintcdn.com/cortex-290c0c42/qRY2zZcIyXqFVeCq/guides/images/zight-2025-11-20-at-2-45-56-pm-1.jpg?fit=max\&auto=format\&n=qRY2zZcIyXqFVeCq\&q=85\&s=07bec996df2acfa1e1e9f558c1665914) ### Step 3: Download the Plugin Template After registering the plugin, Cortex provides a downloadable plugin starter template, including: * React setup * Plugin Context provider * Styling tokens (`--cortex-plugin-*`) * Local development instructions * A preconfigured route structure Download the template from the [Register plugin page](https://app.getcortexapp.com/admin/plugins/new) in Cortex. This template is where you’ll build your visualization. ![](https://mintcdn.com/cortex-290c0c42/qRY2zZcIyXqFVeCq/guides/images/zight-2025-11-20-at-2-47-16-pm.jpg?fit=max\&auto=format\&n=qRY2zZcIyXqFVeCq\&q=85\&s=0580b0722bc88b7e51d9851431810925) ### Step 4: Build the Custom Data Visualization Inside the downloaded template: 1. Add a new component 2. Use the Plugin Context to read the current entity tag 3. Fetch custom data using `CortexApi.proxyFetch()` 4. Render a styled table or any UI you choose Below is a complete example component (`SampleMetadataView.tsx`) that renders the fictional `sample-metadata` object. #### Example Component ```tsx theme={null} import React, { useEffect, useState } from "react"; import { CardTitle } from "@cortexapps/react-plugin-ui"; import { CortexApi } from "@cortexapps/plugin-core"; import { Heading, Section, Subsection } from "./UtilityComponents"; import { usePluginContextProvider } from "./PluginContextProvider"; type SampleMetadata = { service_owner?: string; languages?: string; dependencies?: string; service_tier?: string; last_reviewed?: string; links?: string; }; const SampleMetadataView: React.FC = () => { const context = usePluginContextProvider(); const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { const fetchMetadata = async () => { try { const tag = encodeURIComponent(context.entity.tag); const response = await CortexApi.proxyFetch( `https://api.getcortexapp.com/api/v1/catalog/custom-data?tag=${tag}&key=sample-metadata` ); if (!response.ok) throw new Error(`HTTP ${response.status}`); const json = await response.json(); const entry = Array.isArray(json) ? json[0] : json; setData(entry?.value || null); } catch (e: any) { setError("Unable to load sample metadata"); } finally { setLoading(false); } }; if (context?.entity?.tag) fetchMetadata(); }, [context]); const renderRow = (label: string, value: React.ReactNode) => ( {label} {value || "Not set"} ); return (
Sample Metadata {loading &&
Loading…
} {error &&
{error}
} {!loading && !error && data && (
{renderRow("Service Owner", data.service_owner)} {renderRow("Languages", data.languages)} {renderRow("Dependencies", data.dependencies)} {renderRow("Service Tier", data.service_tier)} {renderRow("Last Reviewed", data.last_reviewed)} {renderRow("Links", data.links)}
)}
); }; export default SampleMetadataView; ``` #### Add the component to `App.tsx` Inside the downloaded template, open `App.tsx`. In a single-view plugin like this, the recommended pattern is to render your visualization directly from `App.tsx`. Here’s what the minimal setup looks like: #### `src/App.tsx` ```tsx theme={null} import React from "react"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import PluginProvider from "./RoutingPluginProvider"; import ErrorBoundary from "./ErrorBoundary"; import SampleMetadataView from "./components/SampleMetadataView"; import "../baseStyles.css"; const App: React.FC = () => { const queryClient = new QueryClient(); return ( ); }; export default App; ``` ### Step 5: Upload and Preview the Plugin in Cortex Once your plugin is ready: 1. Run `npm run build` (or equivalent) 2. [Upload](/streamline/plugins/creating-plugins#step-4-uploading-and-previewing-the-plugin) the generated `UI.html` bundle in the Cortex UI 3. Open an entity of a supported type 4. Select your plugin in the left sidebar 5. Verify your custom visualization displays correctly ![](https://mintcdn.com/cortex-290c0c42/qRY2zZcIyXqFVeCq/guides/images/zight-2025-11-20-at-3-03-34-pm.jpg?fit=max\&auto=format\&n=qRY2zZcIyXqFVeCq\&q=85\&s=8ff067c05e46fc716b4921f3ad295cf9) This gives you a full end-to-end workflow for developing, testing, and launching plugin-based custom data visualizations. # Data verification Source: https://docs.cortex.io/guides/product-areas/data-verification Use [data verification](/configure/settings/entity-settings/verification) to keep your catalog accurate over time. When you start a verification period, Cortex prompts entity owners to confirm details like ownership and metadata, so you can catch stale or incorrect data before it causes problems. These recipes show when to run a verification, like after a large import, a migration, or ahead of an audit. ### [Verify services after AI-based auto-mapping](/guides/ai-excellence/verify-auto-mappings) Confirm ownership is accurate after accepting recommended owners in bulk AI excellence ### [Validate data after migration](/guides/migrations-and-modernization/validate-data) Make sure entity data is up to date after moving it into Cortex Migrations ### [Data verifications for audit readiness](/guides/compliance/data-verification) Schedule regular verifications so your catalog is ready for every audit Compliance # Eng Intelligence Source: https://docs.cortex.io/guides/product-areas/eng-intelligence Use [Eng Intelligence](/improve/eng-intelligence) to turn the data your teams already produce into a clear picture of how software gets built and delivered. Instead of pulling reports from several tools, you can track DORA metrics, PR cycle times, and incident response in one place, and spot what's worth fixing. These recipes show how to use Eng Intelligence dashboards and metrics to answer specific questions about your engineering organization. ### [Measure AI impact](/guides/ai-excellence/measure-ai-impact) Use Eng Intelligence to see how AI tools change the way your teams ship AI excellence ### [Improve bottlenecks in your SDLC](/guides/production-readiness/improve-bottlenecks) Use Eng Intelligence to see how AI tools change the way your teams ship Production readiness ### [Tracking cloud costs](/guides/operational-readiness/tracking-cloud-costs) Use Eng Intelligence to see how AI tools change the way your teams ship Operational readiness # Plugins Source: https://docs.cortex.io/guides/product-areas/plugins Use [plugins](/streamline/plugins) to shape Cortex around the way your organization works. With plugins, you can bring in data from internal systems, connect tools Cortex doesn't support out of the box, and build your own views right where your teams already look. These recipes show how to build plugins that put the information your teams need in front of them. ### [Visualizing custom data in a Plugin](/guides/operational-readiness/visualizing-custom-data-in-a-plugin) Build a plugin page that displays custom data with your own UI Operational readiness # Scorecards Source: https://docs.cortex.io/guides/product-areas/scorecards Use [Scorecards](/standardize/scorecards) to turn your engineering standards into rules that Cortex checks automatically. Instead of keeping best practices in wiki pages and checklists, you can see which entities meet the bar, which don't, and what to fix. These recipes cover common ways to use Scorecards, like preparing your services for AI tools, reducing incident response times, tracking migrations, and enforcing security and compliance standards. ### [Establish consistent AI security controls](/guides/ai-excellence/establish-consistent-ai-security-controls) Apply the same security and compliance standards to every AI model and pipeline AI excellence ### [Set benchmarks for AI readiness](/guides/ai-excellence/set-benchmarks-for-ai-readiness) Check whether your services have the engineering foundations to adopt AI safely AI excellence ### [Prepare for effective use of AI tools](/guides/ai-excellence/prepare-for-effective-use-of-ai-tools) Make sure your repos have the files, safeguards, and integrations AI tools need AI excellence ### [Seasonal readiness Scorecard](/guides/production-readiness/seasonal-readiness-scorecard) Get your services ready before your busiest time of year Production readiness ### [Reduce MTTA](/guides/incident-mgmt/reduce-mtta) Make sure the right people are reachable and acknowledge incidents quickly Incident management ### [Reduce MTTR](/guides/incident-mgmt/reduce-mttr) Restore service faster with clear ownership, runbooks, and escalations Incident management ### [Manage an upcoming EOL for AWS](/guides/migrations-and-modernization/manage-an-upcoming-eol-for-aws) Track which services still need to upgrade RDS, Lambda, and ElastiCache versions Migrations ### [Accelerate migration to K8s](/guides/migrations-and-modernization/accelerate-migration-to-k8s) Track your services' progress moving to Kubernetes and keep the migration on schedule Migrations ### [Ensure SOC 2 compliance](/guides/compliance/soc2) Replace spreadsheet tracking by connecting live system data to SOC 2 controls Compliance ### [Measure DORA progress](/guides/dora/scorecard) Measure your teams against DORA benchmarks and watch the metrics improve DORA metrics ### [Enforce security standards](/guides/security/scorecard) Evaluate every service against your security standards before gaps turn into incidents Security ### [Surface vulnerabilities in failed Scorecard rules](/guides/security/vulnerabilities-rules) Show vulnerability details in rule failure messages so engineers know what to fix Security ### [Surface code coverage in failed Scorecard rules](/guides/security/code-coverage-rules) Show SonarQube code coverage in rule failure messages so engineers know what to fix Security # Workflows Source: https://docs.cortex.io/guides/product-areas/workflows Use [Workflows](/streamline/workflows) to turn everyday engineering tasks into a few clicks. Instead of switching between tools or waiting on a ticket, you can run the whole process from Cortex. These recipes cover common ways to use Workflows, like giving developers access to the tools they need, creating new services with best practices built in, kicking off pipelines, and responding to incidents. ### [Scaffold an ML model project](/guides/ai-excellence/scaffold-ml-model) Start every new machine learning project with best practices built in AI excellence ### [Manage Terraform infrastructure](/guides/production-readiness/terraform) Provision, maintain, and destroy cloud resources from a Workflow Production readiness ### [Standardize new service creation](/guides/production-readiness/standardize-new-service-creation) Create the repo, entity, and Jira ticket for a new service in one run Production readiness ### [Rollback a service during an incident](/guides/incident-mgmt/workflow-rollback) Roll back a service quickly when an incident hits Incident management ### [Create ServiceNow incident](/guides/incident-mgmt/servicenow) Open a ServiceNow incident directly from a Workflow Incident management ### [Automate new dev environment](/guides/dev-onboarding/env-setup-workflow) Create a repo, provision infrastructure with Terraform, and open a PR for an RDS instance Developer onboarding ### [Automate user access to GitHub, PagerDuty, and Jira](/guides/dev-onboarding/automate-user-access-to-github-pagerduty-and-jira) Give new developers access to the tools they need on day one Developer onboarding ### [Automate access to Copilot](/guides/dev-onboarding/automate-user-access-to-copilot) Grant GitHub Copilot access with an approval step or self-service Developer onboarding ### [Kick off a Jenkins pipeline](/guides/operational-readiness/jenkins-workflow) Launch a Jenkins build from Cortex without switching tools Operational readiness ### [Call internal service endpoints](/guides/operational-readiness/internal-endpoints) Reach services behind your firewall with Axon Relay, without exposing them Operational readiness ### [Run a Humanitec pipeline](/guides/operational-readiness/humanitec-pipeline) Call the Humanitec API to run a pipeline from a Workflow Operational readiness ### [Trigger internal Jenkins jobs](/guides/operational-readiness/jenkins-axon) Run Jenkins jobs in your private network without exposing your CI/CD tools Operational readiness ### [Automate sync in ArgoCD](/guides/operational-readiness/argocd-workflow) Sync ArgoCD applications from a Workflow instead of the ArgoCD UI Operational readiness ### [Loop in a JavaScript block and return specified output](/guides/operational-readiness/javascript-looping) Transform data with custom scripts instead of extra tooling Operational readiness ### [Link SOC2 documents to an entity](/guides/compliance/link-soc2-docs) Attach SOC 2 documents to entities without the manual busywork Compliance ### [Bulk accept entity data verifications](/guides/compliance/bulk-accept-entity-data-verifications) Let owners accept verification for all of their entities in one run Compliance # Improve bottlenecks in your software development lifecycle Source: https://docs.cortex.io/guides/production-readiness/improve-bottlenecks You can use Cortex MCP to quickly identify bottlenecks that are slowing your teams down, and use these insights to take action and track progress with Custom Dashboards. ### Step 1: Use Cortex MCP to identify bottlenecks First, you can use [Cortex MCP](/get-started/cortex-ai-assistant/mcp) to quickly identify bottlenecks in your version control metrics across the organization. Use a prompt such as *What are the bottlenecks in my version control metrics org-wide?.* The MCP will respond with an analysis of version control bottlenecks. Review the bottlenecks to understand what areas you should focus on. ![](https://mintcdn.com/cortex-290c0c42/qRY2zZcIyXqFVeCq/guides/images/mcp-bottlenecks.jpg?fit=max\&auto=format\&n=qRY2zZcIyXqFVeCq\&q=85\&s=6037f5cfa288eb1b7083938f211b4df2) In our example, the MCP flags the following: * Review pickup is the primary bottleneck. * Cycle time being lower than any single stage of review latency signals heavy overlap and/or outlier effects. Improvement should focus on accelerating reviewer response. * Some teams have much longer wait times for first review. * Another metric to watch is open PR count per team or repo. #### Follow the MCP's recommended next steps The MCP will also generate a list of suggestions to take action on the identified bottlenecks. In our example, the MCP made the following recommendations: * Set and enforce review SLAs on time to first review. * Use Cortex [Data Explorer](/improve/eng-intelligence/data-explorer) to drill further by repository and reviewer to pinpoint which repos feed the extreme outliers. * Close abandoned PRs. ### Step 2: Create a Custom Dashboard to track progress In Cortex, create a [Custom Dashboard](/improve/eng-intelligence/dashboards/custom) to visualize the bottleneck. Add modules to the dashboard based on what was flagged by Cortex MCP. > **Create modules for the metrics** > > In our example, the metrics flagged were Time to first review and Cycle time. > > 1. Navigate to **Eng Intelligence > Metrics Explorer**. > 2. Click **+New module**, then click the default metric on the page (Cycle time). A modal will open where you can select a new metric.\\ > > ![](https://mintcdn.com/cortex-290c0c42/qRY2zZcIyXqFVeCq/guides/images/new-module.jpg?fit=max\&auto=format\&n=qRY2zZcIyXqFVeCq\&q=85\&s=76aaa0b15ab6e8533dd365f27f27e284) > 3. In the Version control metric category, select "Time to first review." Choose which operation to apply to the chart (average, max, median, min, P95, or sum) then click **View metric**.\\ > > ![](https://mintcdn.com/cortex-290c0c42/qRY2zZcIyXqFVeCq/guides/images/time-to-first-review.jpg?fit=max\&auto=format\&n=qRY2zZcIyXqFVeCq\&q=85\&s=da15b06b42daffc01041b29610a28eb0) > 4. The visualization will appear on the page. In the upper right corner, click **Save as**. Give the module a descriptive name, then click **Save module**. > > Repeat these steps for each metric you want to track. > **Create a Custom Dashboard** > > 1. Navigate to **Eng Intelligence > Dashboards**. In the upper right corner, click **Create Dashboard**. > 2. Enter a descriptive name for the dashboard, then at the bottom of the sidebar, click **Save**. > 1. In our example, since we identified review time as the bottleneck, we name the dashboard "Review time bottleneck." > 3. You will be prompted to select a module to add to your dashboard. Select a module, then at the bottom, click **Close**.\\ > > ![](https://mintcdn.com/cortex-290c0c42/qRY2zZcIyXqFVeCq/guides/images/select-modules.jpg?fit=max\&auto=format\&n=qRY2zZcIyXqFVeCq\&q=85\&s=531d022ee052c222346f2ab9a1c43962) > 4. The page will reload with your module visualization. To add another module, click the **+** icon at the bottom or side of the page. Select a module from the list again, then click **Close**. > > The custom dashboard - "Review time bottleneck" - now contains the two metrics flagged by Cortex MCP, allowing for an easy side-by-side comparison: > > ![](https://mintcdn.com/cortex-290c0c42/qRY2zZcIyXqFVeCq/guides/images/bottleneck-custom.jpg?fit=max\&auto=format\&n=qRY2zZcIyXqFVeCq\&q=85\&s=2d30c99c6477981a712388a7ca988592) # Seasonal readiness Scorecard Source: https://docs.cortex.io/guides/production-readiness/seasonal-readiness-scorecard For organizations that have a busy season, they can implement a seasonal readiness Scorecard to proactively ensure operational efficiency and consistency. You can use our [example rules](/guides/production-readiness/seasonal-readiness-scorecard#example-rules) as a starting point, and you can learn more below about [how customer H\&R Block reduced bugs by 50% year-over-year by implementing a seasonal readiness Scorecard](/guides/production-readiness/seasonal-readiness-scorecard#example-h\&r-block’s-season-readiness-scorecard). ### Example rules The focus areas of this type of Scorecard may be be specific to your organization's needs, but as general guidance, we would recommend creating a Scorecard that contains rules in these key focus areas: > **Operational readiness** > > Example rules: > > * Entity has an owner\\ > > `ownership != null` > * Runbook is linked\\ > > `links("runbook").length > 0` > * Logs are linked\\ > > `links("logs").length > 0` > **Reliability** > > Example rules: > > * SLO coverage\\ > > `slos().length > 0` > > * Before configuring this rule, set up an integration that supports querying SLOs: [Datadog](/ingesting-data-into-cortex/integrations/datadog), [Dynatrace](/ingesting-data-into-cortex/integrations/dynatrace), [Google](/ingesting-data-into-cortex/integrations/google), [Lightstep](/ingesting-data-into-cortex/integrations/lightstep), [New Relic](/ingesting-data-into-cortex/integrations/newrelic), [Prometheus](/ingesting-data-into-cortex/integrations/prometheus), [Splunk Observability Cloud (SignalFx)](/ingesting-data-into-cortex/integrations/splunk-observability), or [Sumo Logic](/ingesting-data-into-cortex/integrations/sumologic). > * Test coverage minimum met\\ > > `captures("test-coverage", sonarqube.metric("coverage") >= 80)` > > * Before configuring this rule, set up an integration with [SonarQube](/ingesting-data-into-cortex/integrations/sonarqube). The [Codecov](/ingesting-data-into-cortex/integrations/codecov) integration also supports querying code coverage. You can [surface these code coverage metrics in failure messages](/guides/security/code-coverage-rules) for failed Scorecard rules. > * Zero critical and high vulnerabilities in Mend\\ > > `mend.vulnerabilities(risk = ["Critical", "High"]).length == 0` > > * Before configuring this rule, set up an integration with [Mend](/ingesting-data-into-cortex/integrations/mend). Other integrations that support querying on vulnerabilities include [Apiiro](/ingesting-data-into-cortex/integrations/apiiro), [Checkmarx](/ingesting-data-into-cortex/integrations/checkmarx), [GitHub](/ingesting-data-into-cortex/integrations/github), [Mend](/ingesting-data-into-cortex/integrations/mend), [Semgrep](/ingesting-data-into-cortex/integrations/semgrep), and [Snyk](/ingesting-data-into-cortex/integrations/snyk). > * On-call rotation has at least one escalation\\ > > `oncall.numOfEscalations() > 1` > > * Before configuring this rule, set up an integration that supports querying on-call: [Opsgenie](/ingesting-data-into-cortex/integrations/opsgenie), [PagerDuty](/ingesting-data-into-cortex/integrations/pagerduty), [Splunk On-Call (VictorOps)](/ingesting-data-into-cortex/integrations/splunk-oncall), or [xMatters](/ingesting-data-into-cortex/integrations/xmatters). > * Datadog monitor is set\\ > > `datadog.monitors().length > 0` > > * Before configuring this rule, set up an integration with [Datadog](/ingesting-data-into-cortex/integrations/datadog). > **Security** > > Example rules: > > * At least one required approval to merge\\ > > `git.numOfRequiredApprovals() > 0`\\ > > * Before configuring this rule, set up a version control integration: [Azure DevOps](/ingesting-data-into-cortex/integrations/azuredevops), [Bitbucket](/ingesting-data-into-cortex/integrations/bitbucket), [GitHub](/ingesting-data-into-cortex/integrations/github), or [GitLab](/ingesting-data-into-cortex/integrations/gitlab). > * Code updated in the last week\\ > > `git.lastCommit().freshness < duration("P7D")` > > * Before configuring this rule, set up a version control integration. > * 0 critical Snyk issues\\ > > `snyk.issues(severity=["CRITICAL"], fixability=["FIXABLE"]) <= 0` > > * Before configuring this rule, set up an integration with Snyk. Other integrations that support querying on vulnerabilities include [Apiiro](/ingesting-data-into-cortex/integrations/apiiro), [Checkmarx](/ingesting-data-into-cortex/integrations/checkmarx), [GitHub](/ingesting-data-into-cortex/integrations/github), [Mend](/ingesting-data-into-cortex/integrations/mend), [Semgrep](/ingesting-data-into-cortex/integrations/semgrep), and [Snyk](/ingesting-data-into-cortex/integrations/snyk). ### Get started with an example Scorecard You can use the example rules above as a starting point for your Scorecard. In this example Scorecard, the levels are organized by focus area. Scorecard levels are progressive, with the last level including the highest priority rules. Based on your organization's needs, you may want to reorder rules, add or remove rules, or rename the levels. You can [create this Scorecard in the UI](/guides/production-readiness/seasonal-readiness-scorecard#create-example-scorecard-via-the-ui), or you can [upload the YAML file via API or GitOps](/guides/production-readiness/seasonal-readiness-scorecard#create-example-scorecard-via-gitops-or-api). **UI** ### Create example Scorecard via the UI #### Step 1: Create the Scorecard and configure its basic details 1. In Cortex, navigate to **Scorecards** and click **+Create Scorecard**. Start with a blank Scorecard. 2. Configure the basic details. * Include a name that helps your users understand the purpose of the Scorecard (e.g., `Season readiness`) and a description. * Learn more about configuring basic fields for Scorecards in [Create a Scorecard](/standardize/scorecards/create). ### Step 2: Add levels and rules 1. Under **Define evaluation rules**, add levels. In our example, we added levels based on focus area: * Operational readiness * Reliability * Security 2. Under a level, click **+Add rule** to add a rule. * For each level, add the [example rules](/guides/production-readiness/seasonal-readiness-scorecard#example-rules) listed earlier in these instructions. 3. At the bottom of the page, click **Save Scorecard**. **API or GitOps** #### Create example Scorecard via GitOps or API When following a [GitOps approach](/configure/gitops), you can add a Scorecard YAML file to your `.cortex/scorecards` directory in your version control repository. Note that GitOps must be enabled for Scorecards in your [GitOps settings](/configure/settings/gitops-settings). You could also use the [Cortex API,](/api/rest/scorecards) where you can submit a Scorecard definition in YAML. > **Seasonal readiness Scorecard YAML** > > Use the YAML file below to add this Scorecard to your workspace via the API or via a GitOps flow. > > ```yaml theme={null} > tag: seasonal-readiness > name: Seasonal Readiness > description: Ensuring services are ready before the busy season > draft: false > notifications: > enabled: true > scoreDropNotificationsEnabled: false > exemptions: > enabled: true > autoApprove: false > userSpecificNotifications: false > ladder: > name: Default Ladder > levels: > - name: Operational readiness > rank: 1 > description: Minimum seasonal readiness > color: "#EBA27E" > - name: Reliability > rank: 2 > description: Top level readiness rules > color: "#B3B3B3" > - name: Security > rank: 3 > color: "#33393F" > rules: > - title: On-call rotation has at least one escalation > expression: oncall.numOfEscalations() > 1 > weight: 1 > level: Reliability > - title: Logs are linked > expression: links("logs").length > 0 > weight: 1 > level: Operational readiness > - title: Entity has owner > description: "For accountability, ensure entities have clear ownership" > expression: ownership != null > weight: 1 > level: Operational readiness > - title: Test coverage minimum met > expression: "captures(\"test-coverage\", sonarqube.metric(\"coverage\") >= 80)" > weight: 1 > level: Reliability > - title: SLO coverage > expression: slos().length > 0 > weight: 1 > level: Reliability > - title: Datadog monitoring is set > expression: datadog.monitors().length > 0 > weight: 1 > level: Reliability > - title: At least one required approval to merge > expression: git.numOfRequiredApprovals() > 0 > weight: 1 > level: Security > - title: Runbook is linked > expression: links("runbook").length > 0 > weight: 1 > level: Operational readiness > - title: Low number of Snyk issues > expression: snyk.issues().length < 5 > weight: 1 > level: Security > - title: Zero critical and high vulnerabilities > expression: "captures(\"critical-vulns\", custom(\"critical_vulnerabilities\"))\ > \ == 0 AND captures(\"high-vulns\", custom(\"high_vulnerabilities\")) == 0" > weight: 1 > level: Reliability > - title: Code updated in the last week > expression: git.lastCommit().freshness < duration("P7D") > weight: 1 > level: Security > filter: > kind: GENERIC > types: > include: > - service > ``` ## Example: H\&R Block's Season Readiness Scorecard As described in their IDPCON talk, H\&R Block implemented a Season Readiness Scorecard ahead of tax season to drive operational consistency. Their Scorecard helped them automatically measure their organization's top priority areas: Security, resiliency, code coverage, and software development lifecycle best practices. They included rules to verify on-call coverage, escalation depth, monitoring setup, SLOs, and package versions. ### Outcome They reduced incidents and bugs by 50% year over year, while automating readiness tracking previously handled manually by six program managers. #### Their next steps To continue proactively meeting organizational benchmarks, they also created [Scaffolder templates](/streamline/workflows/scaffolder) with built-in compliance and coding standards. This allowed them to ensure that all new projects were scaffolded with the best practices baked in. ### See the IDPCON session H\&R Block's Manager of Technology spoke at IDPCON to explain how their organization leveled up developer experience with automation in Cortex: [YouTube video player](https://www.youtube.com/embed/_wLdQ5Fxb_g) # Standardize new service creation Source: https://docs.cortex.io/guides/production-readiness/standardize-new-service-creation Developers often need to spin up new services for use cases like feature development and architecture processes. Doing this manually can be error-prone and inconsistent across teams. To achieve engineering excellence, it is critical to modernize and standardize this practice; you can use a Cortex Workflow to ensure every new service has best practices built in from the start. The Workflow in this example streamlines service creation by guiding you through a form to input service information then automatically handling the rest: creating a new repository based on your input, creating an entity in Cortex that includes custom data and a linked repository, and automatically opening a Jira ticket to ensure visibility and tracking. > [!TIP] > > Cortex customer Archer saves 24 hours per new service created by using Workflows to automate service creation with best practices built in. [Learn more below](/guides/production-readiness/standardize-new-service-creation#example-archer’s-deployment-workflow). ## Create a Workflow to standardize new service creation ### Prerequisites Before getting started: * Create a [Jira API token](https://support.atlassian.com/atlassian-account/docs/manage-api-tokens-for-your-atlassian-account/) with the `write:issue:jira` permission. * Your Cortex role must have the [permissions](/configure/settings/managing-users/permissioning) `Edit Workflows`, `Execute Workflow runs`, `Configure Scaffolder templates`, and `Execute Scaffolder`. * You should have already configured your version control provider integration with `write` access. * Make sure you have already [registered your Scaffolder template](/streamline/workflows/scaffolder). * In this example, we use the [cookiecutter-spring-boot repository](https://github.com/cortex-workshops/cookiecutter-spring-boot). ### Step 1: Configure the Workflow basic settings Follow the steps in the documentation to [create a Workflow](/streamline/workflows/create) and configure its basic settings. ### Step 2: Add blocks to the Workflow Add the following blocks to the Workflow: > **User input** > > This block contains the three fields that a user is prompted to fill out when the Workflow is run. > > 1. Click **+** in the center of the page. In the block library modal, select the **User input** block. > 2. In the side panel, enter a name and unique slug for the block. > 3. Click **+Add user input**. Configure the input: > 1. **Name**: Enter `Service Name`. > 2. **Key**: Enter `service-name`. > 3. **Description**: Optionally enter a description for this input. > 4. **Required**: Toggle this setting on if you want to require your users to enter input for this field. > 5. **Type**: Select `Text`. > 6. Click **Add input**. > 4. Click **+Add user input** again. Configure the input: > 1. **Name**: Enter `Service Tag`. > 2. **Key**: Enter `service-tag`. > 3. **Description**: Optionally enter a description for this input. In our example, we add a description to ensure that users understand what a Cortex tag is in Cortex:\\ > > `The Cortex tag is a unique identifier that's used throughout Cortex. Do not use spaces. Example: my-service` > 4. **Required**: Toggle this setting on if you want to require your users to enter input for this field. > * If you are asking for a unique tag, we recommend setting this field as required. > 5. **Type**: Select `Text`. > 6. Click **Add input**. > 5. Click **+Add user input** again. Configure the input: > 1. **Name**: Enter `Incident Process Documented`. > 2. **Key**: Enter `incident-process-documented`. > 3. **Description**: Optionally enter a description for this input. In our example, we add a description to ensure that users understand what this step is asking for:\\ > > `Has the incident process been submitted to your team lead?` > 4. **Required**: Toggle this setting on if you want to require your users to enter input for this field. > 5. **Type**: Select `Toggle`. > 6. **Default value**: In our example, we set this to `False` to ensure users don't accidentally send a false positive. > 7. Click **Add input**. > 6. Click **Save** at the bottom of the side panel. > > ![The User input step contains three input fields.](https://mintcdn.com/cortex-290c0c42/qRY2zZcIyXqFVeCq/guides/images/user-input-scaffolder-example.jpg?fit=max\&auto=format\&n=qRY2zZcIyXqFVeCq\&q=85\&s=8735452114d0189beef5157aa862dece) > **Scaffolder** > > This block creates a new repository in your connected Git integration, using templating to apply the outputs of the User Input step as the project name, app name, and repository name. > > 1. Click **+** in the center of the page. In the block library modal, select the **Scaffolder** block. > 2. In the side panel, enter a name and unique slug for the block. > 3. Under **Scaffolder template**, select your template. In this example, we use the `Spring Boot Template`. > 4. Select the option to **Create a new repo**. > 5. Add override variables. The **Variable** dropdown pulls in all the variables that are able to be overridden in the Git provider and in the Scaffolder template. In this example, we apply the following overrides: > * **project\_name**: `actions.user-input.outputs.service-name` > * This overrides it with the output of the "Service name" field from the User Input block earlier in the Workflow. > * **creator**: `context.initiatedBy.email` > * This overrides it with the email address of the person who initiated the Workflow. > * **app\_name**: `actions.user-input.outputs.service-name` > * Like the project\_name override, this one also overrides it with the output of the "Service Name" field from the User Input block. > * **publisherRepoName**: `actions.user-input.outputs.service-tag` > * This overrides it with the output of the "Service Tag" field from the User Input block earlier in the Workflow. This ensures that the repo name matches the [Cortex tag](/ingesting-data-into-cortex/entities-overview/entities#cortex-tag). > 6. Click **Save** at the bottom of the side panel. > **Cortex custom data** > > Earlier in the Workflow, the User Input step prompts a user to enter a service name, tag, and to use a toggle to indicate whether the incident process was documented. > > The **Add custom data for entity** block determines where the user's response (the custom data) is recorded. Running this step results in the output of the `Incident Process Documented` toggle being added to an entity. > > 1. Click **+** in the center of the page. In the block library modal, select the **Add custom data for entity** block. > 2. In the side panel, enter a name and unique slug for the block. > 3. Configure the custom data details: > 1. **Entity tag or ID**, use templating to reference the service tag provided by the user during the User Input step: `{{actions.user-input.outputs.service-tag}}` > 2. **Key**: `incident-process-documented` > 3. **Value**: `"{{actions.user-input.outputs.incident-process-documented}}"` > 4. Click **Save** at the bottom of the side panel. > **HTTP request** > > ### Step 4: Add an HTTP request block > > This step creates a Jira ticket for tracking and security review. > > 1. Click **+** in the center of the page. In the block library modal, select the **Add custom data for entity** block. > 2. In the side panel, enter a name and unique slug for the block. > 3. Configure the HTTP request: > 1. **HTTP method**: Select `POST`. > 2. **URL**: Enter your Jira API URL. > 3. **Headers**: Include an authorization header and set the value to your Jira token. > 4. **Payload**: In the payload, you can choose the project in Jira where you want the ticket created, and you can include other information such as the title of the Jira ticket (the `summary`) and the description of the ticket (the `content:text`). See [Jira's API documentation](https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issues/#api-rest-api-3-issue-post) for more information on formatting the payload. In this example, we include the following payload: > > ```json theme={null} > { > "fields": { > "project": { > "key": "SEC" > }, > "summary": "Entity ready for security review.", > "description": { > "type": "doc", > "version": 1, > "content": [ > { > "type": "paragraph", > "content": [ > { > "type": "text", > "text": "New service ready for review." > } > ] > } > ] > }, > "issuetype": { > "name": "Task" > } > } > } > ``` > > 4. Click **Save** at the bottom of the side panel. When you are finished adding blocks, click **Save Workflow** at the top of the page. ### Run the Workflow * In the list of Workflows, locate your new service creation Workflow and click **Run**. * You will be redirected to a page showing the Workflow's steps. The following chain of events occur during the run: > **Workflow run steps** > > 1. The **User Input** block runs, which pauses the Workflow until the Workflow initiator enters a response. > 1. In this example, we enter `Docs test` as the **Service Name**, `docs-test` as a **Service Tag**, and toggle on the option for **Incident Process Documented**. \\ > > ![](https://mintcdn.com/cortex-290c0c42/qRY2zZcIyXqFVeCq/guides/images/user-input-example.jpg?fit=max\&auto=format\&n=qRY2zZcIyXqFVeCq\&q=85\&s=a83c51d001883929c81edbd86c74416c) > 2. The **Scaffolder** block runs, which prompts you to configure and run the Spring Boot Template that was selected while [configuring the Scaffolder step](/guides/production-readiness/standardize-new-service-creation#step-2-add-blocks-to-the-workflow). > 1. Because of the overrides that were configured in the Scaffolder step, the Project Name, App Name, Creator, and Repository fields are pre-filled. The overridden fields cannot be edited unless you select the option to make override fields editable while configuring the Scaffolder block. > 2. During this step, you must also select the organization to create the repository in, include the branch name and a commit message, and choose the visibility of your repo. When you are finished, click **Submit**. A repository will be created in the organization you selected:\\ > > ![](https://mintcdn.com/cortex-290c0c42/qRY2zZcIyXqFVeCq/guides/images/repo-created.jpg?fit=max\&auto=format\&n=qRY2zZcIyXqFVeCq\&q=85\&s=37bc4317d780413f98d48026663a546b) > 3. The **Add custom data** block runs. The newly-created entity for the repository now contains the `incident-process-documented` key and value. You can see this in the **Output** tab of the block during the Workflow run, and in the [entity details page](/ingesting-data-into-cortex/entities-overview/entities/details) **Custom data & metrics** sidebar link:\\ > > ![](https://mintcdn.com/cortex-290c0c42/qRY2zZcIyXqFVeCq/guides/images/custom-data-scaffolder.jpg?fit=max\&auto=format\&n=qRY2zZcIyXqFVeCq\&q=85\&s=e7780fe304f202ed74c5d483f1f15357) > 4. The **HTTP request** block runs. A ticket is created in Jira requesting a review from the security team. The title and description were set automatically based on the payload provided while [configuring the HTTP request step](/guides/production-readiness/standardize-new-service-creation#step-4-add-an-http-request-block): > > ![](https://mintcdn.com/cortex-290c0c42/qRY2zZcIyXqFVeCq/guides/images/scaffolder-jira-step.jpg?fit=max\&auto=format\&n=qRY2zZcIyXqFVeCq\&q=85\&s=2157b4cf7a452ed75a2c4c0eb03310b4) ## Example: Archer's deployment Workflow Cortex customer Archer implemented a Workflow combining scaffolding, infrastructure, deployment configuration, and cloud resources into a single process. All new services follow a consistent, repeatable workflow that includes best practices and requirements by default. ### Outcome * Their teams go from concept to deployed service on a Kubernetes cluster in under 3 hours. * They save 24 hours per new service creation. * They saved an estimated \$72,000 across 30+ Workflow runs in 3 months. ### See the case study Learn more about Archer's process in the case study: [Archer accelerates engineering efficiency with Workflows](https://www.cortex.io/case-studies/archer). # Manage Terraform infrastructure Source: https://docs.cortex.io/guides/production-readiness/terraform You can use Workflows in Cortex to manage different aspects of Terraform infrastructure, including provisioning cloud resources, maintaining the resources, and destroying the resource to remove it from your Cortex workspace. Handling these processes via a Workflow allows you to: * **Automate infrastructure provisioning**: Use a Workflow to trigger the creation of cloud resources (such as AWS EC2 instances) by updating Terraform variables and executing runs * **Enable self-service infrastructure requests**: Using a Workflow to streamline Terraform processes, organizations can enable self-service provisioning for developers. * **Standardize environment bootstrapping:** Using the Scaffolder, teams can bootstrap new projects or environments with pre-defined Terraform templates, ensuring consistency and compliance with organizational standards. See end-to-end Workflow examples in the following pages: * [Provision EC2 instance with Terraform](/guides/production-readiness/terraform/provision) * [Update EC2 instance](/guides/production-readiness/terraform/update) * [Terraform destroy](/guides/production-readiness/terraform/destroy) # Terraform destroy Source: https://docs.cortex.io/guides/production-readiness/terraform/destroy Using a Workflow, you can streamline the process of dismantling infrastructure that was previously provisioned and managed by a Terraform configuration. This Workflow will also remove the resource entity from your Cortex workspace. ## How to use a Workflow in Cortex to destroy a resource with Terraform ### Prerequisite Before getting started, you should have already followed the guide to [Provision an EC2 instance with Terraform](/guides/production-readiness/terraform/provision). #### Considerations * This Workflow makes HTTP calls to [Terraform Cloud](https://www.hashicorp.com/en/products/terraform), but it is possible to call other Terraform orchestrators, such as [Spacelift](https://www.spacelift.io/). * The Terraform orchestrator you use must have an API call to perform the destroy. ### Step 1: Start creating the Workflow Follow the steps in the documentation to [create a Workflow](/streamline/workflows/create) and [configure its basic settings](/streamline/workflows/create#creating-a-workflow). In the Workflow's basic settings, set its scope to apply to the entity type `AWS::EC2::Instance` and the group `terraform`. The prerequisite Workflow [Provision an EC2 instance with Terraform](/guides/production-readiness/terraform/provision) automatically adds the group to the entities it creates. ### Step 2: Add blocks to the Workflow The instructions on this page describe how to create this Workflow in the Cortex UI, but it is also possible to copy the Workflow YAML and add it to your workspace via the [Cortex CLI](https://pypi.org/project/cortexapps-cli/). This allows you to quickly set up the example configuration then iterate on it for your own use case. Expand the tile below to learn more. > **Workflow YAML instructions** > > To upload the Workflow example YAML into your workspace: > > 1. Save the Workflow example YAML file below: > > ```yaml theme={null} > name: "[Terraform Cloud] Destroy" > tag: workflow-terraform-destroy > description: null > isDraft: true > filter: > entityFilter: > typeFilter: > types: > - AWS::EC2::Instance > entityGroupFilter: > entityGroups: > - terraform > excludedEntityGroups: [] > ownershipScope: ALL > type: ENTITY > runResponseTemplate: null > failedRunResponseTemplate: null > actions: > - name: Are You Sure > slug: are-you-sure > schema: > inputs: > - name: Are You Sure? This will also delete it from the Catalog > description: null > key: are-you-sure > required: true > defaultValue: false > type: TOGGLE_FIELD > inputOverrides: [] > type: USER_INPUT > outgoingActions: > - branch > isRootAction: true > - name: Branch > slug: branch > schema: > branches: > - name: "yes" > slug: "yes" > outgoingAction: get-descriptor > expression: "actions[\"are-you-sure\"].outputs[\"are-you-sure\"] == true" > type: CONDITIONAL > fallbackBranch: null > joiningAction: null > type: CONDITIONAL_BRANCH > outgoingActions: > - get-descriptor > isRootAction: false > - name: Get Descriptor > slug: get-descriptor > schema: > expression: .context.entity.descriptor > type: JQ > outgoingActions: > - get-workspace-id > isRootAction: false > - name: Get Workspace ID > slug: get-workspace-id > schema: > expression: .actions."get-descriptor".outputs.result.info."x-cortex-metadata".terraform."workspace-id" > type: JQ > outgoingActions: > - terraform-destroy > isRootAction: false > - name: Terraform Destroy > slug: terraform-destroy > schema: > headers: > Content-Type: application/vnd.api+json > Authorization: "Bearer {{context.secrets.tf_token}}" > httpMethod: POST > payload: |- > { > "data": { > "attributes": { > "is-destroy": true, > "message": "Triggered Destroy", > "variables": [] > }, > "type":"runs", > "relationships": { > "workspace": { > "data": { > "type": "workspaces", > "id": "{{actions.get-workspace-id.outputs.result}}" > } > } > } > } > } > url: https://app.terraform.io/api/v2/runs > type: HTTP_REQUEST > outgoingActions: > - delete-entity > isRootAction: false > - name: Delete entity > slug: delete-entity > schema: > inputs: > entityId: "{{context.entity.tag}}" > integrationAlias: null > actionIdentifier: cortex.deleteEntity > type: ADVANCED_HTTP_REQUEST > outgoingActions: [] > isRootAction: false > runRestrictionPolicies: [] > iconTag: null > variables: [] > ``` > > 2. Use the [Cortex CLI](https://pypi.org/project/cortexapps-cli/) to run this command, using the path to your Workflow YAML file:\\ > > `cortex workflows create -f ` Expand the tiles below to learn about each block in this Workflow and how to configure them in the Cortex UI: > **User input** > > This block prompts the user to confirm that they want to destroy the resource. > > 1. Click **+** in the center of the page. In the block library modal, choose **User input**. > 2. In the block configuration side panel, enter a name and unique slug for this block. > * In this example, we use the name `Are you sure` and the slug `are-you-sure`. > 3. Click **+Add user input**. Add the following: > * **Name**: Are you sure? This will also delete it from the catalog > * **Key**: are-you-sure > * **Type**: Toggle > * **Default value**: This is set to `False` to prevent accidental deletion. > * Click **Add input**. > 4. Save the block. > **Branch** > > During the previous User input step, if the user selects "Yes" when prompted, the Workflow will branch into a set of blocks to destroy the resource. If the user does not select yes, then the Workflow will not continue. > > 1. Click **+** in the center of the page. In the block library modal, choose **Branch**. > 2. In the block configuration side panel, enter a name and unique slug for this block. > * In this example, we use the name `Branch` and the slug `branch`. > 3. Configure the conditional path: > * **Name**: Yes > * **Slug**: yes > * **Path expression**: `actions["are-you-sure"].outputs["are-you-sure"] == true` > > #### Add blocks to the branched path > > The blocks in the path will get the entity descriptor and workspace ID, send an HTTP request to Terraform to destroy the resource, and delete the entity in your Cortex workspace. > > **Data transformations** > > 1. Click **+** under the new path. In the block library modal, choose **Data transformation**. > 2. In the block configuration side panel, enter a name and unique slug for this block. > * In this example, we use the name `Get descriptor` and the slug `get-descriptor`. > 3. Enter a jq expression: > > ```jq theme={null} > .context.entity.descriptor > ``` > > 4. Save the block. > 5. Click **+** under the path. In the block library modal, choose **Data transformation**. > 6. In the block configuration side panel, enter a name and unique slug for this block. In this example, we use the name `Get workspace ID` and the slug `get-workspace-id`. > 7. Enter a jq expression: > > ```jq theme={null} > .actions."get-descriptor".outputs.result.info."x-cortex-metadata".terraform."workspace-id" > ``` > 8. Save the block. > > **HTTP request** > > 1. Click **+** under the new path. In the block library modal, choose **HTTP request**. > 2. In the block configuration side panel, enter a name and unique slug for this block. > * In this example, we use the name `Terraform destroy` and the slug `terraform-destroy`. > 3. Configure the block: > * **HTTP method**: POST > * **URL**: In our example, we set this to:\\ > > `https://app.terraform.io/api/v2/runs` > * **Headers**: Set the following headers: > * `Content-Type`: `application/vnd.api+json` > * `Authorization`: `Bearer {{ context.secrets.tf_token }}` > * **Payload**: In our example, we enter the following: > > ```json theme={null} > { > "data": { > "attributes": { > "is-destroy": true, > "message": "Triggered Destroy", > "variables": [] > }, > "type":"runs", > "relationships": { > "workspace": { > "data": { > "type": "workspaces", > "id": "{{actions.get-workspace-id.outputs.result}}" > } > } > } > } > } > ``` > > 4. Save the block. > > **Delete entity** > > 1. Click **+** under the new path. In the block library modal, choose **Cortex > Delete entity**. > 2. In the block configuration side panel, enter a name and unique slug for this block. > 1. In this example, we use the name `Delete entity` and the slug `delete-entity`. > 3. Under **Entity ID or tag**, enter `{{context.entity.tag}}`. ### Step 3: Run the Workflow When you run the Workflow, the following events happen: * The User input step prompts the user to confirm that they want to delete a resource. * If the user confirms during the first block, then the branch block runs. * The Workflow obtains the entity descriptor, then uses that information to obtain the related workspace ID. * The HTTP request triggers a destroy in Terraform. * The "Delete entity" step uses the entity descriptor obtained in the previous steps to determine which entity to delete. # Provision EC2 instance with Terraform Source: https://docs.cortex.io/guides/production-readiness/terraform/provision This Workflow allows you to gather information about the resources, scaffold a new repository, create a new Terraform workspace, create an entity in your Cortex workspace, then send a message to Slack to confirm that the EC2 instance has been created. ## How to use a Cortex Workflow to provision an EC2 instance with Terraform ### Considerations * This Workflow makes HTTP calls to [Terraform Cloud](https://www.hashicorp.com/en/products/terraform), but it is possible to call other Terraform orchestrators, such as [Spacelift](https://www.spacelift.io/). * This Workflow demonstrates how to create a PR, but if you are using PR automation such as [Atlantis](https://www.runatlantis.io/), then you do not need to include the Async HTTP call to Plan and Apply. ### Step 1: Register the Scaffolder template in Cortex Follow the instructions to [register the Scaffolder template in Cortex](/streamline/workflows/scaffolder). Use the following template: > **Cookiecutter template** > > Save the JSON template below to register in Cortex: > > ```json theme={null} > { > "project_name" :"new-vm", > "resource_name": "my-ec2-instance", > "region": [ "us-east-1","us-east-2", "us-west-1","us-west-2"], > "instance_type": [ "t2.micro", "t2.medium","t2.large"], > "version": "0.2" > } > ``` ### Step 2: Start creating the Workflow Follow the steps in the documentation to [create a Workflow](/streamline/workflows/create) and [configure its basic settings](/streamline/workflows/create#creating-a-workflow). ### Step 3: Add blocks to the Workflow The instructions on this page describe how to create this Workflow in the Cortex UI, but it is also possible to copy the Workflow YAML and add it to your workspace via the [Cortex CLI](https://pypi.org/project/cortexapps-cli/). This allows you to quickly set up the example configuration then iterate on it for your own use case. Expand the tile below to learn more. > **Workflow YAML instructions** > > To upload the Workflow example YAML into your workspace: > > 1. Save the Workflow example YAML file below: > > ```yaml theme={null} > name: "[Terraform Cloud] - New EC2 Instance" > tag: terraform-cloud-new-workspace > description: null > isDraft: false > filter: > type: GLOBAL > runResponseTemplate: |+ > Your EC2 instance has been provisioned! > > please use [this](https://{{ actions.get-region.outputs.result }}.console.aws.amazon.com/ec2/home?region={{ actions.get-region.outputs.result }}#InstanceDetails:instanceId={{actions.get-ec2-id.outputs.result }}) url > > This has also been [added to Cortex](https://app.getcortexapp.com/admin/index?tag={{actions.slugify-resource-name.outputs.result}}) where you can perform Updates on this VM from the Workflows menu! > > failedRunResponseTemplate: null > actions: > - name: Resource Details > slug: resource-details > schema: > inputs: > - name: Resource Name > description: null > key: resource-name > required: true > defaultValue: null > placeholder: my-ec2-instance > validationRegex: null > type: INPUT_FIELD > - name: Resource Size > description: null > key: resource-size > required: false > options: > - t2.micro > - t2.medium > - t2.large > defaultValue: t2.micro > placeholder: null > allowAdditionalOptions: false > type: SELECT_FIELD > - name: Resource Region > description: null > key: resource-region > required: false > options: > - us-east-1 > - us-east-2 > - us-west-1 > - us-west-2 > defaultValue: us-west-2 > placeholder: null > allowAdditionalOptions: false > type: SELECT_FIELD > inputOverrides: [] > type: USER_INPUT > outgoingActions: > - slugify-resource-name > isRootAction: true > - name: Slugify Resource Name > slug: slugify-resource-name > schema: > expression: .actions."resource-details".outputs."resource-name" | ascii_downcase > | gsub(" ";"-") > type: JQ > outgoingActions: > - getting-github-details > isRootAction: false > - name: Getting GitHub Details > slug: getting-github-details > schema: > expression: |- > { > "pr_name" : "PR for " + .actions."slugify-resource-name".outputs.result , > "branch_name" : "branch-for-" + .actions."slugify-resource-name".outputs.result , > "repo_name" : "cremerica/sample-iac-repo", > "path" : "modules/ec2s", > "commit_msg": "Commit automated by Cortex" > } > type: JQ > outgoingActions: > - scaffold-git-repo > isRootAction: false > - name: Scaffold Git Repo > slug: scaffold-git-repo > schema: > scaffolderTemplateId: st2babdd4cc74929f2 > createNewRepository: false > createService: false > inputOverrides: > - inputKey: resource_name > outputVariable: actions.slugify-resource-name.outputs.result > editable: false > type: VALUE > - inputKey: region > outputVariable: actions.resource-details.outputs.resource-region > editable: false > type: VALUE > - inputKey: instance_type > outputVariable: actions.resource-details.outputs.resource-size > editable: false > type: VALUE > - inputKey: publisherRepoName > outputVariable: actions.slugify-resource-name.outputs.result > editable: false > type: VALUE > - inputKey: publisherPullRequestTitle > outputVariable: actions.getting-github-details.outputs.result.pr_name > editable: false > type: VALUE > - inputKey: publisherBranch > outputVariable: actions.getting-github-details.outputs.result.branch_name > editable: false > type: VALUE > - inputKey: publisherRepoFullName > outputVariable: actions.getting-github-details.outputs.result.repo_name > editable: false > type: VALUE > - inputKey: publisherCommitMessage > outputVariable: actions.getting-github-details.outputs.result.commit_msg > editable: false > type: VALUE > - inputKey: project_name > outputVariable: actions.slugify-resource-name.outputs.result > editable: false > type: VALUE > - inputKey: publisherPullRequestBody > outputVariable: actions.getting-github-details.outputs.result.pr_name > editable: false > type: VALUE > type: SCAFFOLDER > outgoingActions: > - merge-a-branch > isRootAction: false > - name: Merge a branch > slug: merge-a-branch > schema: > inputs: > repo: cremerica/sample-iac-repo > base_branch: main > head_branch: "{{actions.getting-github-details.outputs.result.branch_name}}" > commit_message: "y" > integrationAlias: cortex > actionIdentifier: github.mergeBranch > type: ADVANCED_HTTP_REQUEST > outgoingActions: > - create-workspace > isRootAction: false > - name: Create Workspace > slug: create-workspace > schema: > headers: > Content-Type: application/vnd.api+json > Authorization: "Bearer {{ context.secrets.tf_token }}" > httpMethod: POST > payload: "{\n \"data\":{\n \"type\":\"workspaces\",\n \"attributes\"\ > :{\n \"auto-apply\": true,\n \"environment\":\"default\",\n\ > \ \"name\":\"{{actions.slugify-resource-name.outputs.result}}\",\n \ > \ \"terraform-version\":\"1.8.5\",\n \"working-directory\": \"\ > modules/ec2s/{{actions.slugify-resource-name.outputs.result}}\",\n \"\ > resource-count\":0,\n \"vcs-repo\":{\n \"branch\":\"\",\n\ > \ \"identifier\":\"cremerica/sample-iac-repo\",\n \"display-identifier\"\ > :\"cremerica/sample-iac-repo\",\n \"github-app-installation-id\"\ > :\"ghain-d3rQou9dNGew4LVx\",\n \"repository-http-url\":\"https://github.com/cremerica/sample-iac-repo.git}\"\ > ,\n \"service-provider\":\"github_app\"\n },\n \"\ > vcs-repo-identifier\":\"cremerica/sample-iac-repo\",\n \"project\":{\n\ > \ \"data\":{\n \"id\":\"prj-nyRLtYxKHcWLggNU\",\n \ > \ \"type\":\"projects\"\n }\n }\n }\n \ > \ } \n}" > url: "https://app.terraform.io/api/v2/organizations/{{context.secrets.tf_organization}}/workspaces/" > type: HTTP_REQUEST > outgoingActions: > - add-aws-access-key-environment-variable > isRootAction: false > - name: Add AWS Access Key Environment Variable > slug: add-aws-access-key-environment-variable > schema: > headers: > Content-Type: application/vnd.api+json > Authorization: "Bearer {{ context.secrets.tf_token }}" > httpMethod: POST > payload: |- > { > "data": { > "type":"vars", > "attributes": { > "key":"AWS_ACCESS_KEY_ID", > "value":"{{context.secrets.aws_access_key_id}}", > "description":"some description", > "category":"terraform", > "hcl":false, > "sensitive":true > } > } > } > url: "https://app.terraform.io/api/v2/workspaces/{{ actions.create-workspace.outputs.body.data.id\ > \ }}/vars" > type: HTTP_REQUEST > outgoingActions: > - add-aws-secret-key-environment-variable > isRootAction: false > - name: Add AWS Secret Key Environment Variable > slug: add-aws-secret-key-environment-variable > schema: > headers: > Content-Type: application/vnd.api+json > Authorization: "Bearer {{ context.secrets.tf_token }}" > httpMethod: POST > payload: |- > { > "data": { > "type":"vars", > "attributes": { > "key":"AWS_SECRET_ACCESS_KEY", > "value":"{{context.secrets.aws_secret_access_key}}", > "description":"some description", > "category":"terraform", > "hcl":false, > "sensitive":true > } > } > } > url: "https://app.terraform.io/api/v2/workspaces/{{ actions.create-workspace.outputs.body.data.id\ > \ }}/vars" > type: HTTP_REQUEST > outgoingActions: > - plan-and-apply > isRootAction: false > - name: Plan and Apply > slug: plan-and-apply > schema: > headers: > Content-Type: application/vnd.api+json > Authorization: "Bearer {{context.secrets.tf_token}}" > httpMethod: POST > payload: |- > { > "data": { > "attributes": { > "variables": [ > { "key" : "cortex_callback", "value": "\"{{callbackUrl}}\"" }, > { "key" : "cortex_token", "value": "\"{{context.secrets.workflows}}\"" } > ] > }, > "type":"runs", > "relationships": { > "workspace": { > "data": { > "type": "workspaces", > "id": "{{actions.create-workspace.outputs.body.data.id }}" > } > } > } > } > } > url: https://app.terraform.io/api/v2/runs > timeoutInSeconds: 300 > type: HTTP_REQUEST_ASYNC > outgoingActions: > - parse-arn > isRootAction: false > - name: Parse arn > slug: parse-arn > schema: > expression: .actions."plan-and-apply".outputs.result.output.data | split(":") > type: JQ > outgoingActions: > - get-ec2-id > isRootAction: false > - name: Get EC2 ID > slug: get-ec2-id > schema: > expression: ".actions.\"parse-arn\".outputs.result[5] | split(\"/\")[1]" > type: JQ > outgoingActions: > - get-region > isRootAction: false > - name: Get Region > slug: get-region > schema: > expression: ".actions.\"parse-arn\".outputs.result[3]" > type: JQ > outgoingActions: > - get-aws-account > isRootAction: false > - name: Get AWS Account > slug: get-aws-account > schema: > expression: ".actions.\"parse-arn\".outputs.result[4]" > type: JQ > outgoingActions: > - add-entity-to-catalog > isRootAction: false > - name: Add Entity to Catalog > slug: add-entity-to-catalog > schema: > inputs: > body: "openapi: 3.0.1\ninfo:\n title: {{actions.resource-details.outputs.resource-name}}\n\ > \ x-cortex-tag: {{actions.slugify-resource-name.outputs.result}}\n x-cortex-type:\ > \ AWS::EC2::Instance\n x-cortex-infra:\n aws:\n cloudControl:\n \ > \ - type: AWS::EC2::Instance\n region: {{actions.get-region.outputs.result}}\n\ > \ accountId: \"{{actions.get-aws-account.outputs.result }}\"\n \ > \ identifier: {{actions.get-ec2-id.outputs.result}}\n x-cortex-metadata:\n\ > \ terraform:\n workspace-id: {{actions.create-workspace.outputs.body.data.id}}\n\ > \ x-cortex-git:\n github:\n repository: {{actions.getting-github-details.outputs.result.repo_name}}\n\ > \ basepath: modules/ec2s/{{actions.slugify-resource-name.outputs.result}}\n\ > \ x-cortex-groups:\n - terraform \n " > dryRun: false > appendArrays: false > failIfEntityDoesNotExist: false > integrationAlias: null > actionIdentifier: cortex.createOrPatchEntity > type: ADVANCED_HTTP_REQUEST > outgoingActions: > - send-message > isRootAction: false > - name: Send message > slug: send-message > schema: > channel: demos > message: |- > @{{context.initiatedBy.email}} - Your EC2 instance has been povisioned! > > please use [this](https://{{ actions.get-region.outputs.result }}.console.aws.amazon.com/ec2/home?region={{ actions.get-region.outputs.result }}#InstanceDetails:instanceId={{actions.get-ec2-id.outputs.result }}) url > > This has also been [added to Cortex](https://app.getcortexapp.com/admin/index?tag={{actions.slugify-resource-name.outputs.result}}) where you can perform Updates on this VM from the Workflows menu! > type: SLACK > outgoingActions: [] > isRootAction: false > runRestrictionPolicies: [] > iconTag: null > variables: [] > ``` > > 2. Use the [Cortex CLI](https://pypi.org/project/cortexapps-cli/) to run this command, using the path to your Workflow YAML file:\\ > > `cortex workflows create -f ` Expand the tiles below to learn about each block in this Workflow and how to configure them in the Cortex UI: > **User input** > > In this example, we add a User Input block to gather resource details from the user. For the resource size and region, the user can select from the options configured here. > > 1. Click **+** in the center of the page. In the block library modal, choose **User input**. > 2. In the block configuration side panel, enter a name and unique slug for this block. > 1. In this example, we use the name `Resource details` and the slug `resource-details`. > 3. Click **+Add user input**. Add the following: > * **Name**: Resource Name > * **Key**: resource-name > * **Type**: Text > * **Placeholder**: my-ec2-instance > * Click **Add input**. > 4. Click **+Add user input**. Add the following: > * **Name**: Resource Size > * **Key**: resource-size > * **Type**: Select > * **Data source**: Manual > * **Placeholder**: In this example, the resource size options are t2.micro, t2.medium, and t2.large. > * Click **Add input**. > 5. Click **+Add user input**. Add the following: > * **Name**: Resource Region > * **Key**: resource-region > * **Type**: Select > * **Data source**: Manual > * **Placeholder**: In this example, the region options are us-east-1, us-east-2, us-west-1, and us-west-2. > * Click **Add input**. > 6. At the bottom of the side panel, click **Save**. > **Data transformations** > > In this Workflow, we use two Data transformation blocks to reshape the data before scaffolding: > > Create a data transformation to lowercase the resource name: > > 1. Click **+** in the center of the page. In the block library modal, choose **Data transformation**. > 2. In the block configuration side panel, enter a name and unique slug for this block. > 1. In this example, we use the name `Slugify Resource Name` and the slug `slugify-resource-name`. > 3. Add a jq expression to take the output of the previous action, then downcase its characters: > > ```jq theme={null} > .actions."resource-details".outputs."resource-name" | ascii_downcase | gsub(" ";"-") > ``` > > 4. At the bottom of the side panel, click **Save**. > > Create a second data transformation to get GitHub details: > > 1. Click **+** in the center of the page. In the block library modal, choose **Data transformation**. > 2. In the block configuration side panel, enter a name and unique slug for this block. > * In this example, we use the name `Getting GitHub details` and the slug `getting-github-details`. > 3. Add a jq expression to take the output of the previous action, and use that to create a PR name and branch name: > > ```jq theme={null} > { > "pr_name" : "PR for " + .actions."slugify-resource-name".outputs.result , > "branch_name" : "branch-for-" + .actions."slugify-resource-name".outputs.result , > "repo_name" : "example/sample-iac-repo", > "path" : "modules/ec2s", > "commit_msg": "Commit automated by Cortex" > } > ``` > > 4. At the bottom of the side panel, click **Save**. > **Scaffolder** > > This block creates a new repository in your connected Git integration, using templating to apply the outputs of previous blocks to the Scaffolder configuration. > > 1. Click **+** in the center of the page. In the block library modal, select the **Scaffolder** block. > 2. In the side panel, enter a name and unique slug for the block. > 1. In this example, we use the name `Scaffold Git Repo` and the slug `scaffold-git-repo`. > 3. Under **Scaffolder template**, select your template. In this example, we use the `New EC2 Instance` template. > 4. Select the option to **Create a new repo**. > 5. Add override variables. The **Variable** dropdown pulls in all the variables that are able to be overridden in the Git provider and in the Scaffolder template. In this example, we apply the following overrides: > * **resource\_name**: `actions.slugify-resource-name.outputs.result` > * This overrides it with the output of the "Slugify resource name" block earlier in the Workflow. > * **region**: `actions.resource-details.outputs.resource-region` > * This overrides it with the output of the resource region chosen during the "Resource details" block earlier in the Workflow. > * **instance\_type**: `actions.resource-details.outputs.resource-size` > * This overrides it with the output of the resource size chosen during the "Resource details" block earlier in the Workflow. > * **publisherRepoName**: `actions.slugify-resource-name.outputs.result` > * This overrides it with the output of the "Slugify resource name" earlier in the Workflow. > * **publisherPullRequestTitle**: `actions.getting-github-details.outputs.result.pr_name` > * This overrides it with the pr\_name output from the "Getting GitHub details" block earlier in the Workflow. > * **publisherBranch**: `actions.getting-github-details.outputs.result.branch_name` > * This overrides it with the branch\_name output from the "Getting GitHub details" block earlier in the Workflow. > * **publisherRepoFullName**: `actions.getting-github-details.outputs.result.repo_name` > * This overrides it with the repo\_name output from the "Getting GitHub details" block earlier in the Workflow. > * **publisherCommitMessage**: `actions.getting-github-details.outputs.result.commit_msg` > * This overrides it with the commit\_msg output from the "Getting GitHub details" block earlier in the Workflow. > * **project\_name**: `actions.slugify-resource-name.outputs.result` > * This overrides it with the output from the "Slugify resource name" block earlier in the Workflow. > * **publisherPullRequestBody**: `actions.getting-github-details.outputs.result.pr_name` > * This overrides it with the pr\_name output from the "Getting GitHub details" block earlier in the Workflow. > 6. At the bottom of the side panel, click **Save**. > **GitHub merge branch** > > This block sets the head branch name and merges it. > > 1. Click **+** in the center of the page. In the block library modal, select the **GitHub > Merge a branch** block. > 2. In the side panel, enter a name and unique slug for the block. > * In this example, we use the name `Merge a branch` and the slug `merge-a-branch`. > 3. Configure the block: > * **Repository**: Enter your repository name > * **Base branch**: Enter the name of the branch into which changes will be merged, e.g. `main`. > * **Head branch**: Enter the name of the head branch containing the changes to merge. > * In our example, we use the following template to pull the "branch name" output from the earlier Data transformation step whose slug is `getting-github-details`:\\ > > `{{actions.getting-github-details.outputs.result.branch_name}}` > * **Commit message**: Optionally enter a commit message. > 4. At the bottom of the side panel, click **Save**. > **HTTP requests** > > There are three HTTP requests that perform the following actions: Create a workspace in Terraform, add the AWS access key environment variable, and add the AWS secret key environment variable. > > **Create a workspace in Terraform** > > 1. Click **+** in the center of the page. In the block library modal, select the **HTTP request** block. > 2. In the side panel, enter a name and unique slug for the block. > * In this example, we use the name `Create workspace` and the slug `create-workspace`. > 3. Configure the block: > 1. **HTTP method**: POST > 2. **URL**: In our example, we set this to:\\ > > `https://app.terraform.io/api/v2/organizations/{{context.secrets.tf_organization}}/workspaces/` > 3. **Headers**: Set the following headers: > * `Content-Type`: `application/vnd.api+json` > * `Authorization`: `Bearer {{ context.secrets.tf_token }}` > 4. **Payload**: In our example, we enter the following: > > ```json theme={null} > { > "data":{ > "type":"workspaces", > "attributes":{ > "auto-apply": true, > "environment":"default", > "name":"{{actions.slugify-resource-name.outputs.result}}", > "terraform-version":"1.8.5", > "working-directory": "modules/ec2s/{{actions.slugify-resource-name.outputs.result}}", > "resource-count":0, > "vcs-repo":{ > "branch":"", > "identifier":"cremerica/sample-iac-repo", > "display-identifier":"cremerica/sample-iac-repo", > "github-app-installation-id":"ghain-d3rQou9dNGew4LVx", > "repository-http-url":"https://github.com/cremerica/sample-iac-repo.git}", > "service-provider":"github_app" > }, > "vcs-repo-identifier":"cremerica/sample-iac-repo", > "project":{ > "data":{ > "id":"prj-nyRLtYxKHcWLggNU", > "type":"projects" > } > } > } > } > } > ``` > > 4. Save the block. > > **Add the AWS access key environment variable** > > 1. Click **+** in the center of the page. In the block library modal, select the **HTTP request** block. > 2. In the side panel, enter a name and unique slug for the block. > * In this example we use the name `Add AWS Access Key environment variable` and the slug `add-aws-access-key-environment-variable`. > 3. Configure the block: > 1. **HTTP method**: POST > 2. **URL**: In our example, we set this to:\\ > > `https://app.terraform.io/api/v2/workspaces/{{ actions.create-workspace.outputs.body.data.id }}/vars` > 3. **Headers**: Set the following headers: > * `Content-Type`: `application/vnd.api+json` > * `Authorization`: `Bearer {{ context.secrets.tf_token }}` > 4. **Payload**: In our example, we enter the following: > > ```json theme={null} > { > "data": { > "type":"vars", > "attributes": { > "key":"AWS_ACCESS_KEY_ID", > "value":"{{context.secrets.aws_access_key_id}}", > "description":"some description", > "category":"terraform", > "hcl":false, > "sensitive":true > } > } > } > ``` > > 4. Save the block. > > **Add the AWS secret key environment variable** > > 1. Click **+** in the center of the page. In the block library modal, select the **HTTP request** block. > 2. In the side panel, enter a name and unique slug for the block. > * In this example we use the name `Add AWS Secret Key environment variable` and the slug `add-aws-secret-key-environment-variable`. > 3. Configure the block: > 1. **HTTP method**: POST > 2. **URL**: In our example, we set this to:\\ > > `https://app.terraform.io/api/v2/workspaces/{{ actions.create-workspace.outputs.body.data.id }}/vars` > 3. **Headers**: Set the following headers: > * `Content-Type`: `application/vnd.api+json` > * `Authorization`: `Bearer {{ context.secrets.tf_token }}` > 4. **Payload**: In our example, we enter the following: > > ```json theme={null} > { > "data": { > "type":"vars", > "attributes": { > "key":"AWS_SECRET_ACCESS_KEY", > "value":"{{context.secrets.aws_secret_access_key}}", > "description":"some description", > "category":"terraform", > "hcl":false, > "sensitive":true > } > } > } > ``` > > 4. Save the block. > **Async HTTP request** > > Note: If you are using PR automation such as [Atlantis](https://www.runatlantis.io/), then you do not need to include this HTTP call to Plan and Apply. > > 1. Click **+** in the center of the page. In the block library modal, select the **Async HTTP request** block. > 2. In the side panel, enter a name and unique slug for the block. > * In this example we use the name `Plan and Apply` and the slug `plan-and-apply`. > 3. Configure the block: > 1. **HTTP method**: POST > 2. **URL**: In our example, we set this to:\\ > > `https://app.terraform.io/api/v2/runs` > 3. **Headers**: Set the following headers: > * `Content-Type`: `application/vnd.api+json` > * `Authorization`: `Bearer {{ context.secrets.tf_token }}` > 4. **Timeout**: 5 minutes > 5. **Payload**: In our example, we enter the following: > > ```json theme={null} > { > "data": { > "attributes": { > "variables": [ > { "key" : "cortex_callback", "value": "\"{{callbackUrl}}\"" }, > { "key" : "cortex_token", "value": "\"{{context.secrets.workflows}}\"" } > ] > }, > "type":"runs", > "relationships": { > "workspace": { > "data": { > "type": "workspaces", > "id": "{{actions.create-workspace.outputs.body.data.id }}" > } > } > } > } > } > ``` > > 4. Save the block. > **Data transformations** > > This four data transformations take output from previous blocks then parse the ARN, get the EC2 ID, get the AWS region, and get the AWS account. > > **Parse the ARN** > > 1. Click **+** in the center of the page. In the block library modal, select the **Data transformation** block. > 2. In the side panel, enter a name and unique slug for the block. > * In this example we use the name `Parse arn` and the slug `parse-arn`. > 3. Enter a jq expression: > > ```jq theme={null} > .actions."plan-and-apply".outputs.result.output.data | split(":") > ``` > > 4. Save the block. > > **Get EC2 ID** > > 1. Click **+** in the center of the page. In the block library modal, select the **Data transformation** block. > 2. In the side panel, enter a name and unique slug for the block. > * In this example we use the name `Get EC2 ID` and the slug `get-ec2-id`. > 3. Enter a jq expression: > > ```jq theme={null} > .actions."parse-arn".outputs.result[5] | split("/")[1] > ``` > > 4. Save the block. > > **Get region** > > 1. Click **+** in the center of the page. In the block library modal, select the **Data transformation** block. > 2. In the side panel, enter a name and unique slug for the block. > * In this example we use the name `Get region` and the slug `get-region`. > 3. Enter a jq expression: > > ```jq theme={null} > .actions."parse-arn".outputs.result[3] > ``` > > 4. Save the block. > > **Get AWS account** > > 1. Click **+** in the center of the page. In the block library modal, select the **Data transformation** block. > 2. In the side panel, enter a name and unique slug for the block. > * In this example we use the name `Get AWS account` and the slug `get-aws-account`. > 3. Enter a jq expression: > > ```jq theme={null} > .actions."parse-arn".outputs.result[4] > ``` > > 4. Save the block. > **Create or patch entity** > > In this step, we use the output of previous blocks to create a new entity in Cortex. > > 1. Click **+** in the center of the page. In the block library modal, select the **Create or patch entity** block. > 2. In the side panel, enter a name and unique slug for the block. > * In this example we use the name `Add entity to catalog` and the slug `add-entity-to-catalog`. > 3. Under descriptor, enter the following: > > ```yaml theme={null} > openapi: 3.0.1 > info: > title: {{actions.resource-details.outputs.resource-name}} > x-cortex-tag: {{actions.slugify-resource-name.outputs.result}} > x-cortex-type: AWS::EC2::Instance > x-cortex-infra: > aws: > cloudControl: > - type: AWS::EC2::Instance > region: {{actions.get-region.outputs.result}} > accountId: "{{actions.get-aws-account.outputs.result }}" > identifier: {{actions.get-ec2-id.outputs.result}} > x-cortex-metadata: > terraform: > workspace-id: {{actions.create-workspace.outputs.body.data.id}} > x-cortex-git: > github: > repository: {{actions.getting-github-details.outputs.result.repo_name}} > basepath: modules/ec2s/{{actions.slugify-resource-name.outputs.result}} > x-cortex-groups: > - terraform > ``` > **Send Slack message** > > In this step, we use the output of previous steps to send a templated message via Slack informing the user that their EC2 instance has been created.. > > 1. Click **+** in the center of the page. In the block library modal, select the **Slack** block. > 2. In the side panel, enter a name and unique slug for the block. > * In this example we use the name `Send message` and the slug `send-message`. > 3. Select a Slack channel name. > 4. Enter text for the message that will be sent via Slack. In our example, we use the following: > > ``` > @{{context.initiatedBy.email}} - Your EC2 instance has been provisioned! > > please use [this](https://{{ actions.get-region.outputs.result }}.console.aws.amazon.com/ec2/home?region={{ actions.get-region.outputs.result }}#InstanceDetails:instanceId={{actions.get-ec2-id.outputs.result }}) url > > This has also been [added to Cortex](https://app.getcortexapp.com/admin/index?tag={{actions.slugify-resource-name.outputs.result}}) where you can perform Updates on this VM from the Workflows menu! > ``` > > 5. Save the block. ### Step 4: Run the Workflow When you run the Workflow, the following events happen: * The Workflow pauses to collect responses from the user during the User Input step. * The Data transformation steps reshape the responses, then that reformatted data is used to create a repository during the Scaffolder step. * A new Terraform workspace is created, and the AWS access key and secret key variables are included. The async HTTP request block triggers the planning and applying process in Terraform. * The data is transformed, and the reformatted data is used to create an entity in Cortex. * A message is sent in Slack to confirm that the EC2 instance has been provisioned. It includes a link to the EC2 instance and a link to the newly-created entity in Cortex: ![A Slack message confirms the EC2 instance is created.](https://mintcdn.com/cortex-290c0c42/qRY2zZcIyXqFVeCq/guides/images/terraform-slack-example.jpg?fit=max\&auto=format\&n=qRY2zZcIyXqFVeCq\&q=85\&s=d07b2cc3c38e0d632ae1bc59afb5a448) * The entity in Cortex is connected to the repository and to the Terraform workspace. # Update EC2 instance Source: https://docs.cortex.io/guides/production-readiness/terraform/update This Workflow allows you to streamline modifications to an existing EC2 instance. ## How to use a Workflow in Cortex to update an EC2 instance with Terraform ### Prerequisite Before getting started, you should have already followed the guide to [Provision an EC2 instance with Terraform](/guides/production-readiness/terraform/provision). ### Step 1: Start creating the Workflow Follow the steps in the documentation to [create a Workflow](/streamline/workflows/create) and [configure its basic settings](/streamline/workflows/create#creating-a-workflow). In the Workflow's basic settings, set its scope to apply to the entity type `AWS::EC2::Instance` and the group `terraform`. The prerequisite Workflow [Provision an EC2 instance with Terraform](/guides/production-readiness/terraform/provision) automatically adds the group to the entities it creates. ### Step 2: Add blocks to the Workflow The instructions on this page describe how to create this Workflow in the Cortex UI, but it is also possible to copy the Workflow YAML and add it to your workspace via the [Cortex CLI](https://pypi.org/project/cortexapps-cli/). This allows you to quickly set up the example configuration then iterate on it for your own use case. Expand the tile below to learn more. > **Workflow YAML instructions** > > To upload the Workflow example YAML into your workspace: > > 1. Save the Workflow example YAML file below: > > ```yaml theme={null} > name: "[Terraform Cloud] - Update EC2 instance" > tag: update-ec2-instance > description: null > isDraft: true > filter: > entityFilter: > typeFilter: > types: > - AWS::EC2::Instance > entityGroupFilter: null > ownershipScope: ALL > type: ENTITY > runResponseTemplate: null > failedRunResponseTemplate: null > actions: > - name: Get Descriptor > slug: get-descriptor > schema: > expression: .context.entity.descriptor > type: JQ > outgoingActions: > - get-terraform-file > isRootAction: true > - name: Getting Terraform File > slug: get-terraform-file > schema: > inputs: > ref: main > path: "{{actions.get-descriptor.outputs.result.info.x-cortex-git.github.basepath}}/main.tf" > repo: "{{actions.get-descriptor.outputs.result.info.x-cortex-git.github.repository}}" > integrationAlias: cortex > actionIdentifier: github.getFile > type: ADVANCED_HTTP_REQUEST > outgoingActions: > - decoding-file-content > isRootAction: false > - name: Decoding File Content > slug: decoding-file-content > schema: > expression: .actions."get-terraform-file".outputs.response.content | gsub("\n";"") > | @base64d > type: JQ > outgoingActions: > - getting-current-properties > isRootAction: false > - name: Getting Current Properties > slug: getting-current-properties > schema: > script: | > var fileContent = actions['decoding-file-content'].outputs.result > > var fileObject = hcl.parseToObject(fileContent) > > return fileObject > type: JAVASCRIPT > outgoingActions: > - get-current-region > isRootAction: false > - name: Get Current Region > slug: get-current-region > schema: > expression: ".actions.\"getting-current-properties\".outputs.result[0].provider.aws[0].region" > type: JQ > outgoingActions: > - get-current-instance-type > isRootAction: false > - name: Get Current Instance Type > slug: get-current-instance-type > schema: > expression: ".actions.\"getting-current-properties\".outputs.result[0].resource.aws_instance.ubuntu[0].instance_type" > type: JQ > outgoingActions: > - get-current-instance-name > isRootAction: false > - name: Get Current Instance Name > slug: get-current-instance-name > schema: > expression: ".actions.\"getting-current-properties\".outputs.result[0].resource.aws_instance.ubuntu[0].tags.Name" > type: JQ > outgoingActions: > - setting-github-fields > isRootAction: false > - name: Setting GitHub Fields > slug: setting-github-fields > schema: > expression: |- > { > "pr_name" : "PR for " + .actions."get-current-instance-name".outputs.result , > "branch_name" : "branch-for-" + .actions."get-current-instance-name".outputs.result , > "repo_name" : "cremerica/sample-iac-repo", > "commit_msg": "Commit automated by Cortex" > } > type: JQ > outgoingActions: > - user-input > isRootAction: false > - name: User input > slug: user-input > schema: > inputs: > - name: Current Instance Type > description: null > key: current-instance-type > required: false > defaultValue: null > placeholder: null > validationRegex: null > type: INPUT_FIELD > - name: Instance-Type > description: null > key: instance-type > required: false > options: > - t2.micro > - t2.medium > - t2.large > defaultValue: null > placeholder: "" > allowAdditionalOptions: false > type: SELECT_FIELD > - name: Current Region > description: null > key: current-region > required: false > defaultValue: null > placeholder: null > validationRegex: null > type: INPUT_FIELD > - name: New Region > description: null > key: new-region > required: false > options: > - us-west-2 > - us-west-1 > - us-east-1 > - us-east-2 > defaultValue: null > placeholder: null > allowAdditionalOptions: false > type: SELECT_FIELD > inputOverrides: > - inputKey: current-instance-type > outputVariable: actions.get-current-instance-type.outputs.result > editable: false > type: VALUE > - inputKey: current-region > outputVariable: actions.get-current-region.outputs.result > editable: false > type: VALUE > type: USER_INPUT > outgoingActions: > - get-new-instance-type > isRootAction: false > - name: Get New instance Type > slug: get-new-instance-type > schema: > expression: if .actions."user-input".outputs."instance-type" == null then .actions."user-input".outputs."current-instance-type" > else .actions."user-input".outputs."instance-type" end > type: JQ > outgoingActions: > - get-new-region > isRootAction: false > - name: Get New Region > slug: get-new-region > schema: > expression: if .actions."user-input".outputs."new-region" == null then .actions."get-current-region".outputs.result > else .actions."user-input".outputs."new-region" end > type: JQ > outgoingActions: > - scaffolder > isRootAction: false > - name: 'Modify ' > slug: scaffolder > schema: > scaffolderTemplateId: st2babdd4cc74929f2 > createNewRepository: false > createService: false > inputOverrides: > - inputKey: instance_type > outputVariable: actions.get-new-instance-type.outputs.result > editable: true > type: VALUE > - inputKey: resource_name > outputVariable: actions.get-current-instance-name.outputs.result > editable: true > type: VALUE > - inputKey: project_name > outputVariable: actions.get-current-instance-name.outputs.result > editable: true > type: VALUE > - inputKey: publisherRepoFullName > outputVariable: actions.setting-github-fields.outputs.result.repo_name > editable: false > type: VALUE > - inputKey: publisherBranch > outputVariable: actions.setting-github-fields.outputs.result.branch_name > editable: true > type: VALUE > - inputKey: publisherPullRequestTitle > outputVariable: actions.setting-github-fields.outputs.result.pr_name > editable: false > type: VALUE > - inputKey: publisherPullRequestBody > outputVariable: actions.setting-github-fields.outputs.result.pr_name > editable: true > type: VALUE > - inputKey: publisherCommitMessage > outputVariable: actions.setting-github-fields.outputs.result.commit_msg > editable: false > type: VALUE > - inputKey: region > outputVariable: actions.get-new-region.outputs.result > editable: true > type: VALUE > type: SCAFFOLDER > outgoingActions: [] > isRootAction: false > runRestrictionPolicies: [] > iconTag: null > variables: [] > ``` > > 2. Use the [Cortex CLI](https://pypi.org/project/cortexapps-cli/) to run this command, using the path to your Workflow YAML file:\\ > > `cortex workflows create -f ` Expand the tiles below to learn about each block in this Workflow and how to configure them in the Cortex UI: > **Data transformation** > > Get the entity descriptor with a data transformation block. > > 1. Click **+** in the center of the page. In the block library modal, choose **Data transformation**. > 2. In the block configuration side panel, enter a name and unique slug for this block. > 1. In this example, we use the name `Get Descriptor` and the slug `get-descriptor`. > 3. Add a jq expression to get the entity descriptor: > > ```jq theme={null} > .context.entity.descriptor > ``` > > 4. At the bottom of the side panel, click **Save**. > **GitHub get file** > > This block gets the Terraform file you want to update. > > 1. Click **+** in the center of the page. In the block library modal, choose **GitHub > Get file**. > 2. In the block configuration side panel, enter a name and unique slug for this block. > 1. In this example, we use the name `Getting Terraform file` and the slug `get-terraform-file`. > 3. For the Required parameters, configure the following: > * Repository: `{{actions.get-descriptor.outputs.result.info.x-cortex-git.github.repository}}` > * Path: `{{actions.get-descriptor.outputs.result.info.x-cortex-git.github.basepath}}/main.tf` > * Ref: `main` > 4. Save the block. > **Data transformation** > > Take the output from the previous block and decode its file contents. > > 1. Click **+** in the center of the page. In the block library modal, choose **Data transformation**. > 2. In the block configuration side panel, enter a name and unique slug for this block. > 1. In this example, we use the name `Decoding file content` and the slug `decoding-file-content`. > 3. Add a jq expression: > > ```jq theme={null} > .actions."get-terraform-file".outputs.response.content | gsub("\n";"") | @base64d > ``` > > 4. At the bottom of the side panel, click **Save**. > **JavaScript** > > Run a script to get the current properties from the file you got in previous steps of the Workflow. > > 1. Click **+** in the center of the page. In the block library modal, choose **GitHub > Get file**. > 2. In the block configuration side panel, enter a name and unique slug for this block. > 1. In this example, we use the name `Getting current properties` and the slug `getting-current-properties`. > 3. Add a JavaScript expression: > > ```javascript theme={null} > /*#CORTEX_IGNORE*/import {_, YAML, hcl, context, actions, variables, fetch} from './utils.js'; async () => { > var fileContent = actions['decoding-file-content'].outputs.result > > var fileObject = hcl.parseToObject(fileContent) > > return fileObject > > /*#CORTEX_IGNORE*/} > ``` > > 4. Save the block. > **Data transformations** > > Add four Data transformation blocks to reformat the output from previous blocks: > > **Get current region** > > 1. Click **+** in the center of the page. In the block library modal, choose **Data transformation**. > 2. In the block configuration side panel, enter a name and unique slug for this block. > 1. In this example, we use the name `Get current region` and the slug `get-current-region`. > 3. Add a jq expression: > > ```jq theme={null} > .actions."getting-current-properties".outputs.result[0].provider.aws[0].region > ``` > > 4. At the bottom of the side panel, click **Save**. > > **Get current instance type** > > 1. Click **+** in the center of the page. In the block library modal, choose **Data transformation**. > 2. In the block configuration side panel, enter a name and unique slug for this block. > 1. In this example, we use the name `Get current instance type` and the slug `get-current-instance-type`. > 3. Add a jq expression: > > ```jq theme={null} > .actions."getting-current-properties".outputs.result[0].resource.aws_instance.ubuntu[0].instance_type > ``` > > 4. At the bottom of the side panel, click **Save**. > > **Get current instance name** > > 1. Click **+** in the center of the page. In the block library modal, choose **Data transformation**. > 2. In the block configuration side panel, enter a name and unique slug for this block. > 1. In this example, we use the name `Get current instance name` and the slug `get-current-instance-name`. > 3. Add a jq expression: > > ```jq theme={null} > .actions."getting-current-properties".outputs.result[0].resource.aws_instance.ubuntu[0].tags.Name > ``` > > 4. At the bottom of the side panel, click **Save**. > > **Set GitHub fields** > > 1. Click **+** in the center of the page. In the block library modal, choose **Data transformation**. > 2. In the block configuration side panel, enter a name and unique slug for this block. > 1. In this example, we use the name `Setting GitHub fields` and the slug `setting-github-fields`. > 3. Add a jq expression: > > ```jq theme={null} > { > "pr_name" : "PR for " + .actions."get-current-instance-name".outputs.result , > "branch_name" : "branch-for-" + .actions."get-current-instance-name".outputs.result , > "repo_name" : "cremerica/sample-iac-repo", > "commit_msg": "Commit automated by Cortex" > } > ``` > > 4. At the bottom of the side panel, click **Save**. > **User input** > > In this example, we add a User Input block to gather resource details from the output of previous blocks and prompt the user to select the instance type and new region. > > 1. Click **+** in the center of the page. In the block library modal, choose **User input**. > 2. In the block configuration side panel, enter a name and unique slug for this block. > 1. In this example, we use the name `User input` and the slug `user-input`. > 3. Click **+Add user input**. Add the following: > * **Name**: Current instance type > * **Key**: current-instance-type > * **Type**: Text > * **Path to override value**: `actions.get-current-instance-type.outputs.result` > * Click **Add input**. > 4. Click **+Add user input**. Add the following: > * **Name**: Instance type > * **Key**: instance-type > * **Type**: Select > * **Data source**: Manual > * **Placeholder**: In this example, the resource size options are t2.micro, t2.medium, and t2.large. > * Click **Add input**. > 5. Click **+Add user input**. Add the following: > * **Name**: Current region > * **Key**: get-current-region > * **Type**: Text > * **Path to override value**: `actions.get-current-region.outputs.result` > * Click **Add input**. > 6. Click **+Add user input**. Add the following: > * **Name**: New region > * **Key**: new-region > * **Type**: Select > * **Placeholder**: In this example, the options are us-west-2, us-west-1, us-east-1, and us-east-2. > * Click **Add input**. > 7. Save the block. > **Data transformations** > > Use two data transformations to format the new instance type and region that were entered during the previous step: > > **Get new instance type** > > 1. Click **+** in the center of the page. In the block library modal, choose **Data transformation**. > 2. In the block configuration side panel, enter a name and unique slug for this block. > 1. In this example, we use the name `Get new instance type` and the slug `get-new-instance-type`. > 3. Add a jq expression: > > ```jq theme={null} > if .actions."user-input".outputs."instance-type" == null then .actions."user-input".outputs."current-instance-type" else .actions."user-input".outputs."instance-type" end > ``` > > 4. At the bottom of the side panel, click **Save**. > > **Get new region** > > 1. Click **+** in the center of the page. In the block library modal, choose **Data transformation**. > 2. In the block configuration side panel, enter a name and unique slug for this block. > 1. In this example, we use the name `Get new region` and the slug `get-new-region`. > 3. Add a jq expression: > > ```jq theme={null} > if .actions."user-input".outputs."new-region" == null then .actions."get-current-region".outputs.result else .actions."user-input".outputs."new-region" end > ``` > > 4. At the bottom of the side panel, click **Save**. > **Scaffolder** > > Run a Scaffolder to make modifications. In this block, you will configure override variables to pre-fill parts of the Scaffolder template based on the output of previous steps. > > 1. Click **+** in the center of the page. In the block library modal, select the **Scaffolder** block. > 2. In the side panel, enter a name and unique slug for the block. > 1. In this example, we use the name `Modify` and the slug `scaffolder`. > 3. Under **Scaffolder template**, select your template. In this example, we use the `New EC2 Instance` template. > 4. Select the option to **Open a pull request**. > 5. Add override variables. The **Variable** dropdown pulls in all the variables that are able to be overridden in the Git provider and in the Scaffolder template. In this example, we apply the following overrides: > * **instance\_type**: `actions.get-new-instance-type.outputs.result` > * This overrides it with the output of the "Get new instance type" block earlier in the Workflow. > * **resource\_name**: `actions.get-current-instance-name.outputs.result` > * This overrides it with the output of the "Get current instance name" block earlier in the Workflow. > * **project\_name**: `actions.get-current-instance-name.outputs.result` > * This overrides it with the output of the "Get current instance name" block earlier in the Workflow. > * **publisherRepoFullName**: `actions.setting-github-fields.outputs.result.repo_name` > * This overrides it with the output of the "Setting GitHub fields" block earlier in the Workflow. > * **publisherBranch**: `actions.setting-github-fields.outputs.result.branch_name` > * This overrides it with the branch\_name output of the "Setting GitHub fields" block earlier in the Workflow. > * **publisherPullRequestTitle**: `actions.setting-github-fields.outputs.result.pr_name` > * This overrides it with the pr\_name output of the "Setting GitHub fields" block earlier in the Workflow. > * **publisherPullRequestBody**: `actions.setting-github-fields.outputs.result.pr_name` > * This overrides it with the pr\_name output of the "Setting GitHub fields" block earlier in the Workflow. > * **publisherCommitMessage**: `actions.setting-github-fields.outputs.result.commit_msg` > * This overrides it with the commit\_msg output of the "Setting GitHub fields" block earlier in the Workflow. > * **region**: `actions.get-new-region.outputs.result` > * This overrides it with the output of the resource region chosen during the "Get new region" block earlier in the Workflow. > 6. Set a timeout of 5 minutes. > 7. At the bottom of the side panel, click **Save**. ### Step 3: Run the Workflow When you run the Workflow, the following events happen: * The Workflow obtains the entity descriptor and gets the Terraform file. * The Data transformation steps decode the file contents, reshape the data, then use that reformatted data to set fields in GitHub. * The User input step collects the current instance type, new instance type, and current region. * The data is transformed, and the reformatted data is used to apply modifications to the EC2 instance. # Surface code coverage metrics from SonarQube in failed Scorecard rules Source: https://docs.cortex.io/guides/security/code-coverage-rules [CQL captures](/standardize/cql#captures) allow you to extract specific values from entity data when a rule fails, making it easier for engineers to understand what went wrong. A typical use of captures is to show key quality metrics, such as code coverage, or detailed data like vulnerabilities in Scorecard rule failure messages. This helps engineers quickly understand why a rule is failing for an entity. ## Capturing code coverage from SonarQube You can use captures to surface quality metrics such as code coverage from third-party integrations like SonarQube. 1. Decide what data to show in the failure message. In this example, we want to display the code coverage metric reported by SonarQube. 2. While [configuring a Scorecard](/standardize/scorecards/create#step-1-configure-the-basic-scorecard-fields), add a rule using a CQL capture. Use a CQL expression to capture the code coverage metric and apply a threshold:\ `captures("code-cov", sonarqube.metric("coverage")) > 50` 3. Customize the rule’s **Failure message** field to include the captured value. This message will appear when the rule fails (i.e., when coverage is 50% or lower): ``` This entity's code coverage metric from Sonarqube is: {{context.evaluation.captures.code-cov}}% ``` 4. After evaluation, view the Scorecard details. Navigate to the entity that failed the rule. Expand the failure message to view the captured code coverage value. ![](https://mintcdn.com/cortex-290c0c42/qRY2zZcIyXqFVeCq/guides/images/zight-2025-05-23-at-2-34-09-pm.jpg?fit=max\&auto=format\&n=qRY2zZcIyXqFVeCq\&q=85\&s=cb263e83d57be56ce094c524b2d10790) # Enforce security standards Source: https://docs.cortex.io/guides/security/scorecard Launching a Security Scorecard in Cortex allows you to automatically evaluate all services against defined security standards, such as. ownership, code coverage, and vulnerability scans. This ensures gaps are identified proactively rather than being discovered during incidents or audits. To enforce security standards and promote continuous improvement: * You can launch a Security Scorecard. Cortex provides a prebuilt Security [Scorecard](/standardize/scorecards) template that you can use to track security-related standards. * You can [launch an Initiative](/guides/security/scorecard#create-a-security-initiative) associated with the Scorecard, which gives your engineers a deadline for when to complete certain goals. * [Use reports and Cortex MCP](/guides/security/scorecard#measuring-success) to better understand progress and next steps. ## Create a Security Scorecard ### Prerequisites Before using this Scorecard template: * Ensure you have configured integrations for: * Version control: [Azure DevOps](/ingesting-data-into-cortex/integrations/azuredevops), [Bitbucket](/ingesting-data-into-cortex/integrations/bitbucket), [GitHub](/ingesting-data-into-cortex/integrations/github), or [GitLab](/ingesting-data-into-cortex/integrations/gitlab). * [Snyk](/ingesting-data-into-cortex/integrations/snyk) * This Scorecard uses Snyk for its vulnerability rules, but the rules can be modified to check vulnerability data from [Checkmarx](/ingesting-data-into-cortex/integrations/checkmarx), [Mend](/ingesting-data-into-cortex/integrations/mend), [Semgrep](/ingesting-data-into-cortex/integrations/semgrep), [Veracode](/ingesting-data-into-cortex/integrations/veracode), or [Wiz](/ingesting-data-into-cortex/integrations/wiz). * See [CQL Explorer](https://app.getcortexapp.com/admin/queries) in your Cortex workspace for example queries for these integrations. * [SonarQube](/ingesting-data-into-cortex/integrations/sonarqube) * This Scorecard uses SonarQube for its code coverage rule, but the rule can be modified to check code coverage data from [Codecov](/ingesting-data-into-cortex/integrations/codecov). ### Step 1: Create the Scorecard and configure its basic settings **Cortex UI** #### Create the Scorecard in the Cortex UI 1. On the [**Scorecards** page](https://app.getcortexapp.com/admin/scorecards) in your workspace, click **Create Scorecard**. 2. On the `Security Scorecard` template, click **Use**. 3. Configure basic settings, including the Scorecard's name, unique identifier, description, and more. * Learn about configuring the basic settings in the [Creating a Scorecard documentation](/standardize/scorecards/create). **GitOps or API** When following a [GitOps approach](/configure/gitops), you can add a Scorecard YAML file to your `.cortex/scorecards` directory in your version control repository. Note that GitOps must be enabled for Scorecards in your GitOps settings. You could also use the [Cortex API](/api/rest/scorecards), where you can submit a Scorecard definition in YAML. Use the YAML file below to add this Scorecard to your workspace via the API or via a GitOps flow. > **Security Scorecard YAML** > > ```yaml theme={null} > tag: security-scorecard > name: Security Scorecard > description: |- > Enforce security standards across your organization, including code freshness, static analysis, and vulnerability scans. > > (Created from Scorecard template) > draft: false > notifications: > enabled: true > scoreDropNotificationsEnabled: false > exemptions: > enabled: true > autoApprove: false > userSpecificNotifications: false > ladder: > name: Default Ladder > levels: > - name: Bronze > rank: 1 > color: "#c38b5f" > - name: Silver > rank: 2 > color: "#8c9298" > - name: Gold > rank: 3 > color: "#cda400" > rules: > - title: SonarQube analysis uploaded within the last 7 days > expression: sonarqube.freshness() < duration("P7D") > identifier: 0abbfeac-eda7-3a60-a8a3-eaf4d8fb99f5 > weight: 1 > level: Silver > failureMessage: "Make sure SonarQube is properly set up by following the instruction\ > \ in [our docs](https://docs.cortex.io/ingesting-data-into-cortex/integrations/sonarqube)." > - title: Default branch is protected > expression: git.branchProtection() != null > identifier: 21c30af3-6dd6-3bce-bbe5-56e43549015f > weight: 1 > level: Silver > failureMessage: "This rule is only supported for GitLab and GitHub. If you don't\ > \ have a repository specified, you can add one by following the instructions in\ > \ our docs for [GitHub](https://docs.cortex.io/ingesting-data-into-cortex/integrations/github)\ > \ or [GitLab](https://docs.cortex.io/ingesting-data-into-cortex/integrations/gitlab),\ > \ depending on the tool that your team uses." > - title: Has owners > expression: ownership.allOwners().length > 0 > identifier: 92ab2234-ffb1-371b-9488-8ebe3485e503 > weight: 1 > level: Bronze > failureMessage: "Add an owner by following the instructions in [our docs](https://docs.cortex.io/ingesting-data-into-cortex/entities-overview/entities/ownership)." > - title: At least one required approval to merge > expression: git.numOfRequiredApprovals() > 0 > identifier: a148260a-81c3-3201-9692-de99fd08ed16 > weight: 1 > level: Silver > failureMessage: "This rule is only supported for GitLab and GitHub. If you don't\ > \ have a repository specified, you can add one by following the instructions in\ > \ our docs for [GitHub](https://docs.cortex.io/ingesting-data-into-cortex/integrations/github)\ > \ or [GitLab](https://docs.cortex.io/ingesting-data-into-cortex/integrations/gitlab),\ > \ depending on the tool that your team uses." > - title: Has a low number of Snyk issues > expression: snyk.issues().length < 5 > identifier: afb081c6-b875-32af-a5fb-6be8073cd6b4 > weight: 1 > level: Gold > failureMessage: "Make sure Snyk is properly set up by following the instructions\ > \ in [our docs](https://docs.cortex.io/ingesting-data-into-cortex/integrations/snyk)." > - title: Less than 5 SonarQube vulnerabilities > expression: sonarqube.metric("vulnerabilities") < 5 > identifier: b4e82b64-65b6-3d91-af4f-2fca115e17ad > weight: 1 > level: Gold > failureMessage: "Make sure SonarQube is properly set up by following the instruction\ > \ in [our docs](https://docs.cortex.io/ingesting-data-into-cortex/integrations/sonarqube)." > - title: Code coverage is above 80% > expression: sonarqube.metric("coverage") > 80 > identifier: c286f089-c344-3467-a2e2-cec9ab53871f > weight: 1 > level: Silver > failureMessage: "Make sure SonarQube is properly set up by following the instruction\ > \ in [our docs](https://docs.cortex.io/ingesting-data-into-cortex/integrations/sonarqube)." > - title: Less than 5 SonarQube security hotspots > expression: sonarqube.metric("security_hotspots") < 5 > identifier: d93bbdb9-5a4b-387f-9722-a6bd2f42d2a9 > weight: 1 > level: Gold > failureMessage: "Make sure SonarQube is properly set up by following the instruction\ > \ in [our docs](https://docs.cortex.io/ingesting-data-into-cortex/integrations/sonarqube)." > - title: Code last updated in the last week > expression: git.lastCommit().freshness < duration("P7D") > identifier: e76714ba-1a0e-31f9-ba34-930146da413f > weight: 1 > level: Bronze > failureMessage: "You can add a git repository by following the instructions in our\ > \ docs for [version control integrations](https://docs.cortex.io/ingesting-data-into-cortex/integrations#version-control),\ > \ depending on the tool that your team uses." > - title: Has Snyk project > expression: snyk != null > identifier: eef8b87a-6326-3418-bab7-2608059aafd4 > weight: 2 > level: Bronze > failureMessage: "You can add a Snyk project by following the instructions in [our\ > \ docs](https://docs.cortex.io/ingesting-data-into-cortex/integrations/snyk)." > filter: > kind: GENERIC > types: > include: > - service > ``` ### Step 2: Review and modify rules Cortex's templated rules are based on common industry standards: > **Security: Bronze level rules** > > * Has owners\\ > > `ownership.allOwners().length > 0` > * Code updated in the last week\\ > > `git.lastCommit().freshness < duration("P7D")` > * Has Snyk project\\ > > `snyk != null` > **Security: Silver level rules** > > * SonarQube analysis uploaded within last 7 days\\ > > `sonarqube.freshness() < duration("P7D")` > * Default branch is protected\\ > > `git.branchProtection() != null` > * At least one required approval to merge\\ > > `git.numOfRequiredApprovals() > 0` > * Code coverage is above 80%\\ > > `sonarqube.metric("coverage") > 80` > **Security: Gold level rules** > > * Low number of Snyk issues\\ > > `snyk.issues().length < 5` > * Less than 5 SonarQube vulnerabilities\\ > > `sonarqube.metric("vulnerabilities") < 5` > * Less than 5 SonarQube security hotspots\\ > > `sonarqube.metric("security_hotspots") < 5` You can reorder, delete, and edit rules, add more rules to a level, and assign more points to a rule to signify its importance. Behind each rule is a [Cortex Query Language (CQL) ](/standardize/cql)query; you can edit the existing CQL or write your own queries to further refine your rules. ## Create a Security Initiative Follow the steps below to create an Initiative: > **Create a Security Initiative** > > To motivate change by a certain deadline, you can create an Initiative: > > 1. While viewing your Security Scorecard, click **Create Initiative** in the upper right. > 2. Configure the Initiative fields, including a descriptive name so your team members understand the purpose of the Initiative. For example, `Ensure default branch is protected by end of quarter`. > * Make sure to enable notifications so users are notified if an entity they own is failing the Initiative's goal. > 3. Save the Initiative. > > After the Initiative is published, entity owners will be notified if their entity is not meeting the goal. > > Learn more about [creating Initiatives in the docs](/improve/initiatives). ## Measuring success To understand progress of your Scorecard: * Ask [Cortex MCP,](/get-started/cortex-ai-assistant/mcp) "How is my Security Scorecard doing?" The MCP will respond with information on the entities that are failing rules and suggested next steps. * Review reports: The [Bird's Eye report](/improve/reports/birds-eye) gives insight into how entities are performing against the Scorecard by visualizing the data as a heat map:\ ![The Birds eye report shows scorecard progress as a heatmap.](https://mintcdn.com/cortex-290c0c42/qRY2zZcIyXqFVeCq/guides/images/security-birds-eye.jpg?fit=max\&auto=format\&n=qRY2zZcIyXqFVeCq\&q=85\&s=a251a4e6cd14502a18f5768261564a39) You can also review your Engineering Intelligence metrics for impact on key engineering metrics, such as: * **Deployment frequency**: With best practices in place, such as requiring branch protection, you may see a reduction in rework and less failed builds. * **Incident frequency**: You may see less incidents overall with the implementation of rules such as requiring 80% code coverage and proactively ensuring a low number of vulnerabilities. # Surface vulnerability data in failed Scorecard rules Source: https://docs.cortex.io/guides/security/vulnerabilities-rules [CQL captures](/standardize/cql#captures) allow you to extract specific values from entity data when a rule fails, making it easier for engineers to understand what went wrong. A typical use of captures is to show key quality metrics, such as code coverage, or detailed data like vulnerabilities in Scorecard rule failure messages. This helps engineers quickly understand why a rule is failing for an entity. ### Surface security vulnerability information from custom data [#example-2-surface-security-vulnerability-information-from-custom-data](#example-2-surface-security-vulnerability-information-from-custom-data) You can [configure custom data](/ingesting-data-into-cortex/entities-overview/entities/custom-data) to track any information you want to surface, or you can choose to track information pulled in from third-party integrations. 1. Determine what vulnerability data to display. * In this case, custom data is configured to include details like alert name, score, severity, and detection date. Example custom data under key `security-data`: ``` "alerts": [ { "vulnName": "CV-2844", "alertName": "CVA-2844", "vulnScore": 5.2, "alertStatus": "ACTIVE", "productName": "AssetManager", "vulnSeverity": "MEDIUM", "alertDetected": "2025-05-08T10:49:07Z" } ] ``` 2. ​[While configuring](/standardize/scorecards/create#step-1-configure-the-basic-scorecard-fields) a Scorecard, add a rule that uses captures to pull in the data you want to make more visible: `captures("security", custom('security-data')).get("alerts").length == 0` 3. In the rule's **Failure message** field, configure captures to pull in the relevant information. The following example captures vulnerability information from the custom security data into a table: ``` # Your entity is failing because of an unresolved vulnerability ## Table of data | Product Name | Alert Name | Score | Severity | Date Detected | | :---: | :---: | :---: | :---: | :---: | {{#context.evaluation.captures.security.alerts}} | {{productName}} | {{alertName}} | {{vulnScore}} | {{vulnSeverity}} | {{alertDetected}} | {{/context.evaluation.captures.security.alerts}} ``` 4. After evaluation, inspect the failing rule in the Scorecard. Click into the affected entity and expand the rule to see the vulnerability details in a structured format. # Custom metrics Source: https://docs.cortex.io/improve/eng-intelligence/custom-metrics Engineering teams generate data everywhere—incidents resolved, coverage trends, deployment cadence, SLO drift—but most of it lives outside the tools that drive decisions. Custom metrics let you bring that data into Cortex, so the same analytics infrastructure you use for built-in engineering data can work with the metrics that matter most to your organization. Whether you're pulling from an internal system, a tool Cortex doesn't natively integrate with, or computing derived values from existing integration data, custom metrics give you a consistent way to track, visualize, and act on that data. They surface in Data Explorer, on entity pages, and in Scorecards. After defining a custom metric, data can be provided via the following methods: * **API** - Post custom metric data to Cortex via [the API](/api/rest/custom-metrics). * **CQL** - Compute data based on a CQL query that is evaluated by Cortex every 12 hours. ## Use cases Custom metrics are useful any time you have engineering data that lives outside Cortex's built-in integrations, or when you want to derive new meaning from data that's already there. Examples include: * **Incident data from ServiceNow or other ITSM tools.** Track open incident counts, MTTR, or severity trends per service. Example CQL: `custom("servicenow-incidents").length` * **Custom-computed SLO metrics.** If your SLO calculations live in an internal system or don't map cleanly to a native integration, push the computed values directly via API so they're visible alongside the rest of your engineering health data. * **Metrics from homegrown tooling.** Internal platforms, custom CI pipelines, or proprietary monitoring tools can all post metric data to Cortex via API, making them first-class citizens in Eng Intelligence. * **Derived metrics from existing integrations.** Combine or reframe data from tools Cortex already connects to, e.g. code coverage from Codecov (`codecov.codeCoverage()`) or quality metrics from SonarQube (`sonarqube.metric("coverage")`). > [!NOTE] > > When adding static or slowly changing metadata to entities, consider adding custom data instead of custom metrics. [Learn the differences](/ingesting-data-into-cortex/entities-overview/entities/custom-data#custom-data-vs.-custom-metrics) ## Creating a custom metric and adding data ### Prerequisites Users with the following permissions can configure custom metrics: * `Configure Eng Intelligence Custom Metrics` - Allows for creation, editing, and deletion a custom metric definition. Editable fields include name, filter, and CQL expression. This permission also includes the ability to publish the custom metric. * `Manage Eng Intelligence Custom Metric data` - Only required to manage custom metrics via the API. Grants access to the public API for adding and deleting data points on an API custom metric. ### Creating a custom metric via CQL Follow the steps below to create a custom metric using CQL. > [!NOTE] > > Cortex evaluates CQL expressions every 12 hours to check for new metric data. 1. From the main sidebar, click your avatar in the bottom-left corner. 2. Click **Settings**. 3. From the **Settings** menu, scroll to the **Workspace** section, then expand **Eng Intelligence**. 4. Click **Custom metrics**.\ ![Custom metrics option in the Settings sidebar.](https://mintcdn.com/cortex-290c0c42/QcQzHjqU3EBU2R8X/images/custom-metrics-tab.png?fit=max\&auto=format\&n=QcQzHjqU3EBU2R8X\&q=85\&s=4a541f03d24344ae24c6d8fd78a5a73d) 5. In the upper-right corner, click **Add metric**. 6. In the **Custom metrics** side panel, select the **CQL** radio button. 7. Under **Name**, enter a name for the custom metric, e.g. `pager-volume-7d` (required). 8. Optionally, change the key. The key auto-populates based on the custom metric name and is made up of letters, digits, and hyphens. 9. Under **Description**, enter a description of the custom metric. 10. From the **Category** drop-down menu, assign the custom metric a category. This controls where the metric can be found for selection in Data Explorer. 11. Under **Trend color indicator**, set an indicator to match whether higher is better or worse. This controls the color-coding of trends in Data Explorer. 12. Under CQL query, click **Add CQL query**. In the side panel, add a CQL expression to evaluate every 12 hours. The result of the expression must be a number, otherwise validation fails. Click **Save query**. See [Cortex Query Language (CQL)](/standardize/cql) for more information. 13. From the **Entity types** drop-down menu, choose whether to include or exclude specific entity types. 14. Toggle off **Draft** when you’re ready to publish. By default, the custom metric is in draft state and only visible to users with the permission to configure custom metrics. Toggle this setting off to immediately enable the metric within All Metrics and Data Explorer. 15. Click **Add metric**. > [!NOTE] > > The data retention period for custom metric data is 24 months. > [!NOTE] > > Results are not displayed until the end of the previous day. ### Creating a custom metric via API Follow the steps below to create a custom metric using the API. 1. From the main sidebar, click your avatar in the bottom-left corner. 2. Click **Settings**. 3. From the **Settings** menu, scroll to the **Workspace** section, then expand **Eng Intelligence**. 4. Click **Custom metrics**.\ ![Custom metrics option in the Settings sidebar.](https://mintcdn.com/cortex-290c0c42/QcQzHjqU3EBU2R8X/images/custom-metrics-tab.png?fit=max\&auto=format\&n=QcQzHjqU3EBU2R8X\&q=85\&s=4a541f03d24344ae24c6d8fd78a5a73d) 5. In the upper-right corner, click **Add metric**. 6. In the **Custom metrics** side panel, select the **API** radio button. 7. Under **Name**, enter a name for the custom metric, e.g. `pager-volume-7d` (required). 8. Optionally, change the key. The key auto-populates based on the custom metric name and is made up of letters, digits, and hyphens. 9. Under **Description**, enter a description of the custom metric. 10. From the **Category** drop-down menu, assign the custom metric a category. This controls where the metric can be found for selection in Data Explorer. 11. Under **Trend color indicator**, set an indicator to match whether higher is better or worse. This controls the color-coding of trends in Data Explorer. 12. Toggle off **Draft** when you’re ready to publish. By default, the custom metric is in draft state and only visible to users with the permission to configure custom metrics. Toggle this setting off to immediately enable the metric within All Metrics and Data Explorer. 13. Click **Add metric**. You can also define an API custom metric without the UI. Use [Create a custom metric definition](/api/rest/custom-metrics/create-a-custom-metric-definition) in the Cortex API. The API can also list, update, and delete API custom metric definitions, so you can copy definitions between workspaces or manage them as code. CQL custom metrics are read-only through the API. After defining the metric, you can post data to it via the [Cortex API](/api/rest/custom-metrics). Data points default to the current date and time, but results won't appear until the end of the previous day. For information on adding metric data in bulk via the API, refer to [the documentation](/api/rest/custom-metrics). Note that bulk creation of metric data via the API is subject to rate limits and cardinality limits. > [!NOTE] > > The API supports backfilling custom metric data up to two (2) years. ## Editing a custom metric When editing a custom metric, note that the `key` and `type` cannot be changed. To update either, archive the existing metric and recreate it with a new key. All other fields can be edited at any time. Note that editing a CQL custom metric definition makes its historical values inaccessible. **To edit a custom metric**: 1. From the main sidebar, click your avatar in the bottom-left corner. 2. Click **Settings**. 3. From the **Settings** menu, scroll to the **Workspace** section, then expand **Eng Intelligence**. 4. Click **Custom metrics**.\ ![Custom metrics option in the Settings sidebar.](https://mintcdn.com/cortex-290c0c42/QcQzHjqU3EBU2R8X/images/custom-metrics-tab.png?fit=max\&auto=format\&n=QcQzHjqU3EBU2R8X\&q=85\&s=4a541f03d24344ae24c6d8fd78a5a73d) 5. Locate the metric you want to edit, then click the **pencil icon** next to it.\ ![The pencil icon next to a custom metric.](https://mintcdn.com/cortex-290c0c42/QcQzHjqU3EBU2R8X/images/custom-metrics-pencil-icon.png?fit=max\&auto=format\&n=QcQzHjqU3EBU2R8X\&q=85\&s=6f1522970386585da18ec35df4cfca7c) 6. Make any necessary changes, then click **Save metric**. ## Viewing custom metric data Custom metric data is available in the following areas of Cortex: * Data Explorer * Entity details page * All Metrics (Legacy View) #### Viewing custom metric data in Data Explorer From the main sidebar, expand **Eng Intelligence**, then select **Data Explorer**. Custom metrics appear in a list alongside other Eng Intelligence metrics. #### Viewing custom metric data on an entity's details page From an [entity details page](/ingesting-data-into-cortex/entities-overview/entities/details), click **Custom metrics** in the sidebar to view that entity's metrics. ![Custom metrics option in the entity details sidebar.](https://mintcdn.com/cortex-290c0c42/QcQzHjqU3EBU2R8X/images/custom-metric-entity-details.png?fit=max\&auto=format\&n=QcQzHjqU3EBU2R8X\&q=85\&s=47e95d40c85dc975fb9908d957d43af4) #### Viewing custom metric data in All Metrics (Legacy View) From the main sidebar, expand **Eng Intelligence**, then select **All Metrics**. Custom metrics appear in a list alongside other Eng Intelligence metrics. ![Custom metrics displayed via the All Metrics tab.](https://mintcdn.com/cortex-290c0c42/QcQzHjqU3EBU2R8X/images/custom-metrics-all-metrics.png?fit=max\&auto=format\&n=QcQzHjqU3EBU2R8X\&q=85\&s=dbfba2b1f1793659be5f84b3af3ad558) > [!NOTE] > > [Customize your view](/improve/eng-intelligence/eng-intelligence#all-metrics-settings) by reordering or hiding the columns. ## Querying custom metric data with CQL Once a custom metric has data, you can query that data in CQL to build Scorecard rules and reports. The `customMetrics()` function takes the metric's key and a lookback window: `customMetrics(key="error-rate", lookback=duration("P30D"))` ### Aggregating custom metric data `customMetrics()` returns a list of data points, not a list of numbers. Each data point is a record with two fields: * `value` - The numeric value recorded for the data point. * `timestamp` - The date the data point was recorded. Aggregation functions like `average()` and `sum()` only work on a list of numbers or a list of durations, so you can't apply them to the result of `customMetrics()` directly. Use `map()` to pull the field you want into its own list first, then aggregate: ``` customMetrics(key="error-rate", lookback=duration("P30D")).map((m) => m.value).average() ``` Without `map()`, the query returns the error "Could not apply average to non-numeric and non-duration element": ``` customMetrics(key="error-rate", lookback=duration("P30D")).average() ``` > [!WARNING] > > If a metric has no data points in the lookback window, `average()` returns the error "Cannot take average of empty list." Choose a lookback window long enough to always include at least one data point. # Dashboards Source: https://docs.cortex.io/improve/eng-intelligence/dashboards Eng Intelligence dashboards give engineering leaders and teams real-time visibility into the metrics that matter most—delivery performance, team velocity, incident trends, and AI tool adoption. Each dashboard pulls directly from your Cortex catalog, so the data is always grounded in your actual services and teams. And because dashboards are natively integrated with Scorecards and Initiatives, you can move from spotting a problem to driving action without leaving Cortex. Whether you're a leader looking for an org-wide view or a team lead investigating a slowdown in your release process, dashboards give you the right level of detail to understand what's happening and why. See the documentation linked below to learn more about each dashboard: * [DORA Dashboard](/improve/eng-intelligence/dora-dashboard) - Visualize the four key DORA metrics (cycle time, deployment frequency, change failure rate, and MTTR) to understand how fast, reliable, and efficient your engineering organization is over time. * [Velocity Dashboard](/improve/eng-intelligence/velocity-dashboard) - Monitor version control metrics such as PR cycle time, PR size, and PR success rate to identify bottlenecks in your development process and track improvement over time. * [AI impact for GitHub Copilot](/improve/eng-intelligence/dashboards/ai-impact) - Track Copilot adoption and engagement across your engineering teams. See how adoption rates correlate with delivery and reliability metrics at the team level, compare performance between Copilot users and non-users over the last seven (7) days, and monitor org-wide adoption trends over time. * [Custom Dashboards](/improve/eng-intelligence/dashboards/custom) - Build tailored views by combining any combination of Eng Intelligence metrics into a single, shareable dashboard that's useful for team-specific reviews, executive reporting, or tracking progress on a specific initiative. # AI impact dashboard for GitHub Copilot Source: https://docs.cortex.io/improve/eng-intelligence/dashboards/ai-impact PUBLIC BETA > [!NOTE] > > The AI Impact Dashboard for Copilot is available to all cloud customers as a Public Beta feature. You can provide us [feedback here](https://forms.gle/wW86fGy8Cq2weVte7). The AI Impact Dashboard provides insight into Copilot adoption and engagement across your engineering teams, including visualizations for: * Impact by team AI adoption rate * Correlate team adoption rate to delivery and reliability metrics. Adoption rates are provided daily by comparing active users against Copilot seats. * Impact of Copilot users vs. non-Copilot users * Compare delivery and reliability side-by-side between users who leveraged AI tools within the last 7 days, and those who did not. Understand whether recent AI usage affects engineering performance. * AI adoption trends * View the overall trends for AI adoption across your organization. Use these insights to identify issues and [drive continuous improvement](/improve/eng-intelligence/dashboards/ai-impact#driving-continuous-improvement). ![One of the AI Impact charts shows merged PR metrics for AI users vs. non-AI users.](https://mintcdn.com/cortex-290c0c42/WsEW6MxYeKygvxWi/images/ai-users-mergedPRs-copilot.jpg?fit=max\&auto=format\&n=WsEW6MxYeKygvxWi\&q=85\&s=fbc2df3a789a706b0c55ad0b864c8fcc) ## Using the AI Impact Dashboard ### Prerequisites Before getting started: * You must have [GitHub integration](/ingesting-data-into-cortex/integrations/github) configured. See instructions below for each integration method: * Cortex GitHub app * If configured before October 14, 2025, you must [re-authorize your Cortex GitHub app](https://support.getcortexapp.com/hc/en-us/articles/41736643663387-Why-is-Cortex-requesting-that-I-re-authorize-the-GitHub-app-for-Copilot-metric-permissions) to accept two new permissions. * Custom GitHub App * Add the following permission to your custom GitHub App: `admin:org read` * Personal Access Token * Add the following permission to your PAT: `admin:org read` * In Cortex, you must have the `View Eng Intelligence` permission to view the dashboard, and you must have the `Configure Eng Intelligence` permission to configure it. ### View the Dashboard Navigate to [**Eng Intelligence > Dashboards**](https://app.getcortexapp.com/admin/eng-intelligence/dashboards) to see the full list of Cortex-built and [Custom Dashboards](/improve/eng-intelligence/dashboards/custom) available in your workspace. Click the **Copilot Dashboard**. This Dashboard contains multiple charts that you can filter and compare with key engineering metrics: > **Impact by team AI adoption rate** > > View the impact that a team's AI adoption rate has on their cycle time, deployment frequency, incident frequency, merged PRs, PR size, time to resolution, and work items completed. > > Hover over the data in the graph to see more information about a team and its metrics: > > ![Hover over the Team AI adoption rate chart to learn more about a metric point.](https://mintcdn.com/cortex-290c0c42/K6GZjp5BfPGK-s1-/images/team-ai-adoption-chart.jpg?fit=max\&auto=format\&n=K6GZjp5BfPGK-s1-\&q=85\&s=cfbf0764f5a4e60c25b0296fb151b582) > > Eng Intelligence compares active users against Copilot seats once daily. > **Copilot users vs. Non-Copilot users** > > See the impact that using AI, or not using AI, has on cycle time, merged PRs, PR size, time to resolution, and work items completed. Cortex automatically creates an "AI Usage" user label that is attached to any team member who was active in Copilot within the last 7 days. > > Hover over the data in the graph to see more information about the metrics: > > ![Hover over the chart to learn more about a metric point.](https://mintcdn.com/cortex-290c0c42/WsEW6MxYeKygvxWi/images/ai-user-impact-chart.jpg?fit=max\&auto=format\&n=WsEW6MxYeKygvxWi\&q=85\&s=525e30e163492ddad040f15d6eeba807) > **Copilot adoption over time** > > View your overall Copilot adoption metrics over time: > > ![See Copilot adoption metrics in the graph.](https://mintcdn.com/cortex-290c0c42/Z-yTwwLdih7PmvB6/images/copilot-adoption-graph.jpg?fit=max\&auto=format\&n=Z-yTwwLdih7PmvB6\&q=85\&s=1d50405c74980c602bb2b29781aeeb35) ### Filter and configure the Dashboard #### Overlay a data point To overlay a data point, click the dropdown in the upper left corner of a chart: ![Click the dropdown in the upper left to choose a data point.](https://mintcdn.com/cortex-290c0c42/K6GZjp5BfPGK-s1-/images/select-metric-ai-charts.jpg?fit=max\&auto=format\&n=K6GZjp5BfPGK-s1-\&q=85\&s=3acb605872536a793b4b36ffe0d07f21) #### Filter the chart You can filter at two levels: * **Dashboard level** - Click **Filter** at the top of the dashboard to apply a filter across all charts at once. The Copilot dashboard supports **Domain** and **Team** as dashboard-level filters. * **Chart level** - Click **Filter** in the upper-right corner of an individual chart to apply filters for group, owner, repository, user label, and more. Chart-level filters override dashboard-level filters for that chart. ## Driving continuous improvement Use the AI Impact Dashboard to track and correlate key AI adoption metrics with engineering performance metrics. These insights allow you to identify issues in your processes, which enables the ability to take action and drive improvements. **Example scenario**: You view your dashboard and notice that teams who have higher rates of AI adoption have a lower average cycle time (the time it takes for a single PR to go through the entire coding process). However, you also see a spike in incident frequency for those teams. * **Identify the issue**: You conclude that their process is more efficient, but as a tradeoff, they're shipping code that causes more incidents. You brainstorm with the affected engineering teams to learn how their processes have changed since adopting AI. You learn that SonarQube code coverage is lower than it has been previously. * **Take action**: You already have an [AI Readiness Scorecard](/solutions/ai-readiness/configure#step-2-configure-scorecards-to-track-ai-readiness-standards) launched, and you see that the rule "Test coverage minimum met" is failing. You can create an [Initiative](/standardize/scorecards/create#create-initiative-from-scorecard) on that Scorecard to ask developers to meet a particular rule by a specified deadline. In this case, you create an Initiative that asks the developers to pass the failing rule (i.e., they need to ensure higher than 80% test coverage) by the end of the month. * Initiatives and Scorecard tasks appear as to-do items on a developer's [homepage](/streamline/homepage) in Cortex. * **Review the dashboard**: As developers work toward meeting the requirements, check back in on the dashboard for a real-time update into their progress. # Custom dashboards Source: https://docs.cortex.io/improve/eng-intelligence/dashboards/custom Combine metrics from multiple sources into a unified view > [!NOTE] > > Custom Dashboards is available to all customers as a Public Beta feature. You can provide us [feedback here](https://forms.gle/xazu6auWuMGqMKRt7). Custom dashboards let you build shared views of the engineering metrics that matter most to your organization. Combine saved modules from across your data sources into a single, focused view, then share it with your team so everyone is working from the same picture. Use custom dashboards to: * **Aggregate metrics across sources** - Pull together modules from version control, deployments, incidents, project management, and more into one dashboard. * **Tailor views by team or use case** - Build dashboards scoped to specific teams, workflows, or engineering goals, e.g. an OpEx review, a DORA deep-dive, a sprint health check. * **Share insights across your org** - Dashboards are visible to anyone with the `View Eng Intelligence` permission, so stakeholders get the context they need without manual reporting. * **Surface trends and drive action** - Spot bottlenecks, track progress toward goals, and make data-driven decisions from a single view. **Example dashboards** | Dashboard | What it tracks | | - | - | | **Team health** | PR cycle time, deployment frequency, and incident rate for a specific engineering team | | **Delivery health** | Story points completed, PR throughput, and deploy frequency across a quarter | | **Incident response** | MTTR, incident frequency, change failure rate, and deployment volume | | **OpEx review** | DORA metrics, on-call load, and SLA compliance for leadership reviews | | **Platform reliability** | Change failure rate, rollback frequency, and time to resolution by service | | **Sprint overview** | Work items completed, cycle time, and PR review turnaround for a given sprint | ## Creating a custom dashboard ### Prerequisites 1. You must have the `Configure Eng Intelligence` permission. 2. Make sure you have configured metric modules and saved them in Data Explorer. **To create a custom dashboard**: 1. From the main sidebar, expand **Eng Intelligence**, then click **Dashboards**. 2. In the upper-right corner, click **Create Dashboard**. 3. In the Create dashboard side panel, do the following: 1. Under **Dashboard name**, enter a name for the dashboard (required). 2. Under **Description**, enter an overview of the dashboard. 3. Under **Display icon**, select an icon to represent the dashboard. 4. Click **Create dashboard**. The **Saved modules** side panel opens. 4. From the **Saved modules** side panel, select an existing metric module to add to your dashboard. After selecting a module, you're directed to the dashboard. * To create a new module, click **Create module** to open the Data Explorer, configure your metric, and save it as a module. Then navigate back to Dashboards to add it to your dashboard. 5. To add more modules, click **Add module**. Repeat as necessary.\ ![](https://mintcdn.com/cortex-290c0c42/QcQzHjqU3EBU2R8X/images/custom-dashboard-add.png?fit=max\&auto=format\&n=QcQzHjqU3EBU2R8X\&q=85\&s=984c956cc29634ded23a6a2b84de3163) 6. To remove a module, click its **Remove icon**. > [!TIP] > > You can add as many modules to a custom dashboard as you need. # Managing custom dashboards Source: https://docs.cortex.io/improve/eng-intelligence/dashboards/custom/managing-custom-dashboards This article covers sharing, editing, and filtering custom dashboards. See [Custom dashboards](/improve/eng-intelligence/dashboards/custom/managing-custom-dashboards) for instructions on creating a dashboard. ## Sharing a custom dashboard Dashboards are automatically visible within your organization to users with the `View Eng Intelligence` permission, so everyone can view the same insights and stay aligned. **To create a share link to send to another user**: 1. From the main sidebar, expand **Eng Intelligence**, then click **Dashboards**. 2. Select the dashboard you want to share. 3. In the upper-right corner, click the **Overflow menu** icon. 4. Select **Share**.\ ![](https://mintcdn.com/cortex-290c0c42/QcQzHjqU3EBU2R8X/images/custom-dashboard-share.png?fit=max\&auto=format\&n=QcQzHjqU3EBU2R8X\&q=85\&s=f84143d336b8f8a61c9353b91c5c15b8) ## Editing a custom dashboard 1. From the main sidebar, expand **Eng Intelligence**, then click **Dashboards**. 2. Select the dashboard you want to edit. 3. In the upper-right corner, click the **Edit**. 4. Make any necessary changes including removing and adding modules. See [Creating a custom dashboard](/improve/eng-intelligence/dashboards/custom/managing-custom-dashboards#creating-a-custom-dashboard) for more information. 5. Click **Save**. ## **Using dashboard-level filters** Dashboard-level filters let you apply a consistent scope across all modules in a dashboard at once. Instead of setting the same team, date range, or domain filter on every module individually, you set it once at the top and it propagates to all applicable modules automatically. ### **In edit mode** To add a dashboard-level filter, click **Add filter** at the top of the dashboard while in edit mode. Select one or more filters from the global filter list; your selections are saved as part of the dashboard definition. ![](https://mintlify.s3.us-west-1.amazonaws.com/cortex-290c0c42/images/Screenshot%202026-06-24%20at%2002.21.53%20PM.png) When you add a dashboard-level filter, Cortex will display a message confirming that it will override the same filter if it's also set on an individual module. **Date filter defaults:** * Dashboards created after this feature launched automatically include a date filter. You can remove it. * Dashboards created before this feature launched do not have a date filter automatically applied. ### **In view mode** Dashboard-level filters appear at the top of the dashboard. Setting a filter there applies it immediately to all modules that support it. If a filter isn't applicable to a module (for example, applying a Domain filter to an AI Adoption rate module), that module is unaffected. You can still override a filter for an individual module as module-level filters take precedence over dashboard-level filters for that module. If a dashboard-level date filter is set, individual module date filters are hidden. If no dashboard-level date filter is defined, module-level date filters remain visible. # Data Explorer Source: https://docs.cortex.io/improve/eng-intelligence/data-explorer Formerly 'Metrics Explorer Data Explorer is your window into the metrics that matter. Analyze trends over time, drill into individual data points, and uncover the patterns shaping your development process. Whether you're diagnosing a slowdown or looking for opportunities to improve, Data Explorer gives you the visibility to act with confidence. Found a view you'll want to revisit? Save it as a **module** and skip the work of reapplying filters and display settings every time. Report modules make it effortless to keep an eye on the metrics you care about—like cycle time for a specific team or time period—and they double as building blocks for [custom dashboards](/improve/eng-intelligence/dashboards/custom), so the insights you've curated can power views across your organization. ## Using Data Explorer ### Step 1: Selecting a metric to view Users with the `View Dev Metrics` permission can select a metric to view. The Data Explorer provides three view options, allowing you to choose the format that best fits your analysis: * **Chart** - A standard line chart designed for visualizing a single metric over time. Use this view when you want to track trends or fluctuations in one specific measurement. * **Table** - A tabular layout that displays multiple metrics at once, including Scorecard scores, making it ideal for side-by-side comparisons and detailed analysis. The tabular view also supports a hierarchical, nested structure similar to the [Bird's Eye](/improve/reports/birds-eye) report for drilling into grouped data. * **KPI** - A compact widget that shows a single metric with its current value, a trend comparison (directional arrow, percentage/absolute change), and an optional mini chart. This gives engineering leaders an at-a-glance, standardized way to highlight a key metric. #### **Configuring chart view** 1. From the main sidebar, expand **Eng Intelligence**, then select **Data Explorer**. 2. In the right pane, select **Chart**.\ ![](https://mintcdn.com/cortex-290c0c42/QcQzHjqU3EBU2R8X/images/de-chart.png?fit=max\&auto=format\&n=QcQzHjqU3EBU2R8X\&q=85\&s=55c088544a40310d3d5db542be030ccb) 3. By default, the **cycle time** metric is displayed. To select a different metric, click the tab below **Data** in the right pane. The **Metrics** window opens.\ ![](https://mintcdn.com/cortex-290c0c42/QcQzHjqU3EBU2R8X/images/de-default-metric.png?fit=max\&auto=format\&n=QcQzHjqU3EBU2R8X\&q=85\&s=5a3e4663ee0f0e0de372a82bfe6d225f) 4. Select a metric to view. * Cortex organizes metrics into six categories: Custom, Deployment, Incident, Project management, Version control, and AI tools, each with its own set of available metrics. Refer to [Available metrics in Data Explorer](/improve/eng-intelligence/data-explorer/available-metrics-in-data-explorer) for definitions. 5. Click **View metric**. The chart updates, reflecting the new metric. * By default, the data uses a time range of the last 30 days, but you can [select a different time range](/improve/eng-intelligence/data-explorer#filtering-by-time-range). Metrics can be [grouped by](/improve/eng-intelligence/data-explorer#grouping-metrics-chart-and-table-views) team, owner, repository, entity, and more. 6. Optionally, toggle off **Show table** in the right pane to hide the metric overview below the graph. #### Configuring table view 1. From the main sidebar, expand **Eng Intelligence**, then select **Data Explorer**. 2. In the right pane, select **Table**.\ ![](https://mintcdn.com/cortex-290c0c42/jF7ejFzeAkCGjvGG/images/de-table.png?fit=max\&auto=format\&n=jF7ejFzeAkCGjvGG\&q=85\&s=7edd80d7a80274f915f5c5391d112cad) 3. In the right pane, click **Add column**. The **Metrics** window opens. 4. Select a metric to view. * Cortex organizes metrics into six categories: Custom, Deployment, Incident, Project management, Version control, and AI tools, each with its own set of available metrics. Refer to [Available metrics in Data Explorer](/improve/eng-intelligence/data-explorer/available-metrics-in-data-explorer) for definitions. * Table view also supports three entity data categories: Custom data, Entity definition, and Entity metadata. Use these to bring entity attributes into the table alongside your metrics. Refer to [Entity data in table view](/improve/eng-intelligence/data-explorer/available-metrics-in-data-explorer#entity-data-in-table-view) for definitions. * Table view also supports Scorecards as a metric. Select a Scorecard, then choose **Score %** or **Level** to add the result as a column alongside your metrics. Refer to [Scorecards in table view](/improve/eng-intelligence/data-explorer/available-metrics-in-data-explorer#scorecards-table-view-only) for definitions. 5. Click **View metric**. The table updates, reflecting the new metric. * By default, the data uses a time range of the last 30 days, but you can [select a different time range](/improve/eng-intelligence/data-explorer#filtering-by-time-range). Metrics can be [grouped by](/improve/eng-intelligence/data-explorer#grouping-metrics-chart-and-table-views) team, owner, repository, entity, and more. 6. To remove a metric from the tabular view, click the **overflow menu icon** next to the metric's name, then select **Delete column**.\ ![](https://mintcdn.com/cortex-290c0c42/jF7ejFzeAkCGjvGG/images/de-remove-column.png?fit=max\&auto=format\&n=jF7ejFzeAkCGjvGG\&q=85\&s=d943370b15cb21d1c31f8ed927c88c97) > [!NOTE] > > Entity data columns describe the entity's current state, so they aren't affected by the time range or time attribute filters. Those filters still apply to the metric columns in the same table. #### **Configuring KPI view** 1. From the main sidebar, expand **Eng Intelligence**, then select **Data Explorer**. 2. In the right pane, select **KPI**.\ ![](https://mintcdn.com/cortex-290c0c42/QcQzHjqU3EBU2R8X/images/de-kpi.png?fit=max\&auto=format\&n=QcQzHjqU3EBU2R8X\&q=85\&s=b0cf9c0d60ca6b043c6084769ec920fb) 3. By default, the **cycle time** metric is displayed. To select a different metric, click the tab below **Metric** in the right pane. The **Metrics** window opens. 4. Select a metric to view. * Cortex organizes metrics into six categories: Custom, Deployment, Incident, Project management, Version control, and AI tools, each with its own set of available metrics. Refer to [Available metrics in Data Explorer](/improve/eng-intelligence/data-explorer/available-metrics-in-data-explorer) for definitions. 5. Click **View metric**. The chart updates, reflecting the new metric. * By default, the data uses a time range of the last 30 days, but you can [select a different time range](/improve/eng-intelligence/data-explorer#filtering-by-time-range). 6. Optionally, toggle off the following card options: 1. **Show module header** - Hides the card's header for a cleaner, more minimal look 2. **Show chart preview** - Hides the mini chart when you only want the metric value and trend 3. **Show trend** - Hides the trend indicator (arrow and percentage change). If toggled on, use the **Comparison format** drop-down menu to display the trend in percentage or absolute terms. ### Step 2: Filtering and grouping metrics Users with the `View Dev Metrics` permission can filter and group metrics. You can filter and group metrics by individual, entity, PR, or owner, and you can filter the chart/table by time range, teams, author, and repository. You can also sort the columns. > [!NOTE] > > To filter or group metrics by individual people, you also need the `View Eng Intelligence User Dimensions` permission. Without it, you can still view metrics, but options for individual PR authors and reviewers, deployers, incident assignees, work item assignees, AI tool users, and entity owners don't appear in **Filter**, **Group by**, or autocomplete suggestions. Team- and entity-level options are still available. The Admin and Manager roles include this permission by default. #### Filtering metrics To filter by metrics such as entity, team, repo, or user, click **Filter** in the upper-right corner of the graph. If using the KPI view, **Filter** appears in the card's header. ![The 'Filter' option in Data Explorer.](https://mintcdn.com/cortex-290c0c42/QcQzHjqU3EBU2R8X/images/de-filter.png?fit=max\&auto=format\&n=QcQzHjqU3EBU2R8X\&q=85\&s=878290a5cb24a6a61a56a1b97ffe6721) Configure a single filter or a combination of filters. When you are done adding filters, click **Apply** at the bottom of the filter window. When filtering by teams or domains, **Include child teams** **/** **Include child domains** is toggled on by default, so the full team hierarchy rolls up: * **Entity owner (Team)** includes entities owned by the selected team and any of its nested sub-teams. * **Team** includes contributors who belong to the selected team or any of its nested sub-teams. Toggle this off to limit to direct ownership or membership only. > [!NOTE] > > The **Team owner** filter works differently. It only includes entities owned directly by the selected team, never its child teams. To include child teams' entities, use **Entity owner (Team)** with **Include child teams** on. See the [full list of filters](/improve/eng-intelligence/data-explorer/data-explorer-reference) and their definitions. #### Filtering by time range To filter by time period, click the **time range** filter in the upper-right corner of the graph. By default, **Last 30 days** is displayed. If using the KPI view, **time range** appears in the card's header. ![](https://mintcdn.com/cortex-290c0c42/jF7ejFzeAkCGjvGG/images/de-time-range.png?fit=max\&auto=format\&n=jF7ejFzeAkCGjvGG\&q=85\&s=b5d4e54d5bdd99a7d7418ee4ca3eed6f) Select a new time range and configure the dates. Optionally, toggle on **Exclude weekends** to remove Saturday and Sunday from aggregations and visualizations. Because activity typically dips on weekends, excluding them eliminates recurring noise and makes trends easier to spot. The graph automatically reloads. To change the grouping of the time range in the graph, click **Display** in the upper-right corner of the graph: ![](https://mintcdn.com/cortex-290c0c42/QcQzHjqU3EBU2R8X/images/de-display.png?fit=max\&auto=format\&n=QcQzHjqU3EBU2R8X\&q=85\&s=4419c698e6dee3b87594d561e15b086a) You can choose whether to display the data grouped by day, week, or month. #### Filtering by time attribute A pull request has several dates attached to it: when it was opened, when its first commit landed, when it was merged, and so on. The **time attribute** filter tells Data Explorer which of these dates to use when placing each PR on the timeline. Changing it doesn't change the metric you're measuring; it changes which time bucket each PR falls into, and therefore which PRs appear inside your selected time range. For version control and PR-related metrics, click the **time attribute** filter in the upper-right corner of the graph. If using the KPI view, the time attribute filter appears in the card's header. ![](https://mintcdn.com/cortex-290c0c42/jF7ejFzeAkCGjvGG/images/de-time-attribute.png?fit=max\&auto=format\&n=jF7ejFzeAkCGjvGG\&q=85\&s=92e06eb3006609d5f381bc33911e907b) **Example** Say a PR was opened on May 28 and merged on June 3, and you're viewing a chart with a time range set for the last 30 days. * With the time attribute set to **Open date**, the PR counts toward May. * With it set to **Close/merge date**, the same PR counts toward June. If the time range was "June only," that PR would appear when filtering by close/merge date but disappear when filtering by open date, even though nothing about the PR changed. When a PR seems to be missing from (or unexpectedly present in) a report, the time attribute is usually why. **Available time attributes** | Time attribute | Anchors the PR to... | Use it to answer... | | - | - | - | | **Open date** | When the PR was opened | ***How much work was started in this period?*** | | **Close/merge date** | When the PR was merged or closed | ***How much work shipped in this period?*** (Best for throughput and "what did we deliver" reporting) | | **First commit date** | The timestamp of the PR's first commit | ***When did coding actually begin, regardless of when the PR was opened?*** | | **Date first authored** | When the PR was first authored | ***When did authoring begin for cycle-time analysis?*** | | **First review date** | When the PR received its first review | ***When did review activity happen in this period?*** | | **Approval date** | When the PR was approved | ***When did PRs get approved (as opposed to opened or merged)?*** | | **Date last updated** | The most recent activity on the PR | ***Which PRs saw activity in this period, regardless of when they opened?*** | > [!NOTE] > > For most throughput and delivery reporting, **Close/merge date** is the best defaultas it reflects work that actually shipped. Switch to **Open date** or **First commit date** when you care about when work started rather than when it finished. #### Grouping metrics (chart and table views) To group your metrics differently, click the **Group by** drop-down in the right pane and select an option: ![](https://mintcdn.com/cortex-290c0c42/QcQzHjqU3EBU2R8X/images/de-group-by.png?fit=max\&auto=format\&n=QcQzHjqU3EBU2R8X\&q=85\&s=11ab8934d4caecb117ab913da4ded053) When you select a grouping with an inherent hierarchy, such as Team, Entity owner, or Domain, a **Show hierarchy** toggle appears. Enable it to see metrics aggregated by hierarchy level and drill down into nested groups, similar to the hierarchy views in the [Bird's Eye](/improve/reports/birds-eye) and [All Scorecards](/improve/reports/all-scorecards) reports. The **Group by** drop-down also includes a **Relationships** section, listing the custom entity relationship types defined in your catalog. Select a relationship type to roll metrics up through that relationship. See the [full list of grouping options](/improve/eng-intelligence/data-explorer/data-explorer-reference#group-by-definitions). > [!NOTE] > > The metrics segmented by team are based on the individual users within that team. In order to have data appear, the teams must have members and the team's [identity mappings](/configure/settings/managing-users/identity-mapping) must be configured. #### Sorting the columns (chart and table views) > [!NOTE] > > Sorting is only available if **Show hierarchy** is toggled off. To sort data within the graph, click in the **Sort rows** field in the right pane. Select an option to sort by. Note that options differ depending on the metric you're viewing. ![](https://mintcdn.com/cortex-290c0c42/jF7ejFzeAkCGjvGG/images/de-sort.png?fit=max\&auto=format\&n=jF7ejFzeAkCGjvGG\&q=85\&s=a9f8286c6f94591bec6088f134fdac56) ### Step 3: Saving the view Users with the `Edit Eng Intel Dashboards` permission can save a view as a report. After setting up a view with your preferred metric, filters, and time range, you can save it as a report in Cortex. Note that Cortex refers to these saved reports as **modules**. 1. While viewing a graph, click **Save As** in the upper-right corner of the page. The **Save module** side panel opens. 2. Below **Module name**, enter a name for the report (required). 3. Below **Description**, enter a description of the report. 4. Below **Display icon**, select an icon for the report. 5. Click **Save module**. The report is saved as a module and can be found via **Eng Intelligence > Modules**. From here you can: * Add it to a [custom dashboard](/improve/eng-intelligence/dashboards/custom) * Reopen it at any time without reconfiguring filters * Rename, update metric/filter settings, and re-save as needed * Locate the report, then click the **overflow icon**. Select **Edit** to reconfigure the graph or **Rename** to change the name of the report. * Create a duplicate of the report * Locate the report, then click the **overflow icon**. Select **Duplicate**. * Share a link with team members * Locate the report, then click the **overflow icon**. Select **Share**. The URL is copied to your clipboard. The URL query parameters include timestamps, so the shared Data Explorer page reflects the same results across different timezones. * Delete when no longer needed * Locate the report, then click the **overflow icon**. Select **Delete**. > [!NOTE] > > To encourage transparency and shared focus, every saved module and edit is automatically available to all members of your Eng Intelligence team. ### Step 4: Exporting to CSV Users with the `View Dev Metrics` permission can export data. Chart and table views can be exported as a CSV file. Cortex runs the export on its own servers instead of in your browser, so the file contains every row in the view, not just the rows currently loaded on the page. CSV exports follow the same `View Eng Intelligence User Dimensions` restriction as filtering and grouping. If you don't have the permission, the export doesn't break data out by individual people. > [!NOTE] > > CSV export is available in chart and table views. To export the data behind a KPI view, switch to chart or table view for the same metric. 1. From the main sidebar, expand **Eng Intelligence**, then select **Data Explorer**. 2. Configure the view you want to export, including the metric, filters, and time range. 3. In the upper-right corner of the page, click **Export CSV**. A toast appears in the lower-right corner of the screen showing the status of the export. 4. Do one of the following: * Wait for the export to finish. When the toast shows a green check mark and **Check your downloads**, the file is available in your browser's downloads. * Click **Email me** in the toast. Cortex sends you the file when it's ready, so you can navigate away or close the page without losing the export. This is useful for large exports, which can take a while to build. > [!NOTE] > > Exports are flat: one row per entity, regardless of how the view is grouped. If you've set a **Group by** option or toggled on **Show hierarchy**, the export still returns a single flat list of entities. Grouped and hierarchical exports aren't supported yet. ### Understanding aggregation types When you view a metric in Data Explorer, you can choose how the individual data points (e.g. each PR's Time to Merge) are aggregated into a single headline number. The aggregation you choose changes the story the number tells, but it does **not** change which metric or which underlying dates are being measured. > [!NOTE] > > #### **Aggregations are only comparable within the same metric** > > A P95 of 'Time to Merge' and a median of 'Cycle Time' measure different things over different date ranges, so their values can't be meaningfully compared. Before comparing two numbers, confirm that the metric name shown at the top of the module is the same for both; changing the aggregation should not change the metric you're measuring. | Aggregation | What it tells you | | - | - | | **Average** (mean) | The sum of all values divided by the number of values. Useful for a general sense of the typical result, but sensitive to outliers. | | **Median** (P50) | The middle value—half of your data points are faster and half are slower. More resistant to outliers than the average. | | **P95** | The value that 95% of your data points come in under. Represents the slow tail; the experience of your slowest 5%. | | **Min / Max** | The single fastest or slowest value in the range. | | **Sum** | The total across all values (used for count-style custom metrics). | | **Latest** | The most recent data point in the selected time range, with no aggregation. Returns no value if the range has no data points. Available for custom metrics only. | > [!NOTE] > > #### **Why P95 is usually higher than the median or average** > > Most PR-timing metrics are right-skewed, meaning the majority of PRs complete quickly, and a small number take much longer. For this kind of data, P95 will almost always be higher than both the median and the average, because P95 deliberately sits out in the slow tail while the average is pulled down by the fast majority. > > This is expected and correct. By definition, P95 is always greater than or equal to the median (P50) **for the same metric**. If P95 ever appears lower than the median or average, you are more than likely comparing two different metrics. # Available metrics in Data Explorer Source: https://docs.cortex.io/improve/eng-intelligence/data-explorer/available-metrics-in-data-explorer > [!NOTE] > > Note that Cortex-provided metrics in Data Explorer sync on a scheduled basis, updating every four (4) hours. [Custom metrics](/improve/eng-intelligence/custom-metrics) have their own sync schedules. ## Accessing metrics in Data Explorer Follow the steps below to access metrics in Data Explorer. 1. From the main sidebar, expand **Eng Intelligence**, then select **Data Explorer**. 2. In the right pane, click the tab below **Data**. The **Metrics** window opens.\ ![The 'Data' section in Data Explorer.](https://mintcdn.com/cortex-290c0c42/QcQzHjqU3EBU2R8X/images/de-default-metric.png?fit=max\&auto=format\&n=QcQzHjqU3EBU2R8X\&q=85\&s=5a3e4663ee0f0e0de372a82bfe6d225f) 3. Select a metric to view, then click **View metric**. The chart updates automatically based on the metric you selected.\ ![The 'View metric' button in the Metrics window.](https://mintcdn.com/cortex-290c0c42/QcQzHjqU3EBU2R8X/images/de-metrics-window.png?fit=max\&auto=format\&n=QcQzHjqU3EBU2R8X\&q=85\&s=7938c49073cf14465fa2a5666879b2bb) 4. Repeat steps 2 and 3 as necessary. ## Available metrics ### AI tools > [!NOTE] > > AI tool metrics are available to cloud customers in the [beta program](/resources/beta). AI usage metrics are pulled from [GitHub Copilot](/ingesting-data-into-cortex/integrations/github). | Metric | Definition | | - | - | | **AI adoption rate** | The percentage of licensed seats that were active users of AI coding tools in a given time period. **Calculation**: `Copilot active users / Copilot total seats` | | **Active AI users** | The number of users who used AI coding tools in a given time period. Cortex automatically labels users as `AI User` (active in the last 7 days) or `Non-AI User` (no Copilot activity in the last 30 days). **Calculation**: `Copilot active users` | ### Deployment metrics Deploy metrics are pulled from the [Cortex deploys API](/api/rest/deploys). | Metric | Definition | | - | - | | **Change failure rate** | The percentage of deployments that cause a failure in production. **Best practice**: Aim to reduce your change failure rate over time. A rate below 15% aligns with DORA's elite benchmarks and indicates strong software delivery performance. **Calculation**: `Number of rollbacks / number of deployments created` | | **Deployment frequency** | The number of deployments over a given period of time. **Best practice**: Depending on your organization, a successful benchmark could be multiple deployments per day or per week. | | **Rollback frequency** | The number of rollbacks over a given period of time. **Best practice**: While there isn't an explicit benchmark, you should aim to minimize rollback rates. A low rollback rate generally aligns with a low change failure rate. | ### Incident metrics Incident metrics are pulled from [PagerDuty](/ingesting-data-into-cortex/integrations/pagerduty). | Metric | Definition and calculation | | - | - | | **Incident frequency** | The number of incidents over a given period of time.When you drill in to metric points below, view data per incident: • Incident title • Status • Incident URL • Date triggered • Date resolved • Urgency • Time to resolution**Best practice**: There is no universal benchmark. It's recommended to track trends and establish baselines within your organization. | | **Time to resolution** | The amount of time it takes for an incident to be resolved.When you drill in to metric points, view data per incident: • Incident title • Status • Incident URL • Date triggered • Date resolved • Urgency • Time to resolution**Best practice**: Benchmarks vary by system criticality. Aim for under one (1) day for less critical systems, under 1 hour for critical ones. **Calculation**: `Incident resolution time - incident opened time` | ### Project management metrics Project management metrics are pulled from [Jira](/ingesting-data-into-cortex/integrations/jira). > [!NOTE] > > Project management metrics do not support JQL entity mapping. If you configured a [default JQL query per entity](/ingesting-data-into-cortex/integrations/jira#set-a-default-jql-query-for-your-jira-integration), it is not applied when viewing, filtering, or segmenting these metrics in Data Explorer. | Metric | Definition and calculation | | - | - | | **Story points completed** | The sum of story points completed in a given time period.When you drill in to metric points below the graph, view data per work item: • External key • Work item assignee • Assignee email • Work item title • Work item status • Work item type • Created date • Resolved date • Priority • Labels • Components • Story points completed**Best practice**: Establish a baseline per team, as story point values can be unique to each team. Use this metric to understand capacity trends. | | **Work item lead time** | The time it takes from when a work item is created to when the work item is completed.When you drill in to metric points below the graph, view data per work item: • External key • Work item assignee • Assignee email • Work item title • Work item status • Work item type • Created date • Resolved date • Priority • Labels • Components • Status category • Work item lead time**Best practice**: Lower lead times indicate a smoother process. Track trends to identify process inefficiencies and improve throughput. **Calculation**: `Work item resolved date – Work item created date`. | | **Work items completed** | The number of work items completed over a given period of time.When you drill in to metric points below the graph, view data per work item: • External key • Work item assignee • Assignee email • Work item title • Work item status • Work item type • Created date • Resolved date • Priority • Labels • Components**Best practice**: Review this measure alongside how many story points have been completed; this enables you to balance both quantity and effort, ensuring teams aren't favoring lower value tasks in exchange for higher numbers of items completed. | | **Work items created** | The number of work items created over a given period of time.When you drill in to metric points below the graph, view data per work item: • External key • Work item assignee • Assignee email • Work item title • Work item status • Work item type • Created date • Resolved date • Priority • Labels • Components**Best practice**: Monitor this metric alongside delivery rates. If items are created faster than completed, it signals queue backlogs. | ### Version control metrics Version control metrics are pulled from [Azure DevOps](/ingesting-data-into-cortex/integrations/azuredevops), [Bitbucket](/ingesting-data-into-cortex/integrations/bitbucket), [GitHub](/ingesting-data-into-cortex/integrations/github), and [GitLab](/ingesting-data-into-cortex/integrations/gitlab). > [!NOTE] > > Pull request–related metrics include PRs from any branch. | Metric | Definition and calculation | | - | - | | **Cycle time** | The date a PR is authored to when the PR is merged. This represents the time it takes for a single PR to go through the entire coding process. Falls back to first commit date if authored date is not available. Note: This metric is not supported for [Azure DevOps](/ingesting-data-into-cortex/integrations/azuredevops) or [Bitbucket](/ingesting-data-into-cortex/integrations/bitbucket). When you drill in to metric points below the graph, view data per PR: • PR name • Author • PR status • First commit date • Date closed • Cycle time**Best practice**: Aim for lower cycle times to ensure a faster feedback loop and reduced context switching. Rather than benchmarking the overall cycle time, set benchmarks for the individual parts of the cycle (time to open, time to approve, time to first review, time to merge). | | **Closed PRs** | The number of PRs closed in a given time period.When you drill in to metric points below the graph, view data per PR: • PR name • Author • PR status • Date closed**Best practice**: A high ratio of merged-to-closed PRs signals an effective review cycle. | | **Merged PRs** | The number of PRs merged in a given time period.When you drill in to metric points below the graph, view data per PR: • PR name • Author • PR status • Date closed**Best practice**: A high ratio of merged-to-closed PRs signals an effective review cycle. | | **Number of comments per PR** | The number of comments on a pull request.When you drill in to metric points below the graph, view data per PR: • PR name • Author • PR status • First commit date • Number of comments per PR**Best practice**: This measure indicates review depth and collaboration. A lower number may signal superficial reviews. | | **Number of unique PR authors** | The number of unique PR authors.When you drill in to metric points below the graph, view data per PR: • PR name • Author • PR status • First commit date • Date opened • Time to open • This is the time between the first commit date and the date opened.**Best practice**: A larger number across projects can signal distributed ownership, while a consistently low number can point to bottlenecks or team burnout. | | **Opened PRs** | The number of PRs opened in a given time period.When you drill in to metric points below the graph, view data per PR: • PR name • Author • PR status • Date closed**Best practice**: Persistent backlog can indicate process inefficiencies, such as a slow review process. | | **PR reviews count** | The number of reviews on a PR.When you drill in to metric points below the graph, view more data: • PR name • Reviewer • Review date**Best practice**: A higher number can indicate complex changes or low initial quality. A lower number could indicate approvals without thorough review and validation. | | **PR size** | The number of lines of code modified in a PR.Note: This metric is not supported for [Azure DevOps](/ingesting-data-into-cortex/integrations/azuredevops) or [Bitbucket](/ingesting-data-into-cortex/integrations/bitbucket).When you drill in to metric points below the graph, view data per PR: • PR name • Author • PR status • Number of lines added • Number of lines deleted • PR size**Best practice**: Smaller PRs lead to faster reviews, fewer mistakes, and increased velocity. Aim for less than 400 lines, but adjust this benchmark as needed to improve review quality and velocity. | | **Success rate** | The percentage of PRs that are opened and eventually merged in a given time frame.When you drill in to metric points below the graph, view data per PR: • PR name • Author • PR status • Date opened • Date closed**Best practice**: Higher success rates can indicate better quality code and reviews, but note that it is also important to understand the reasoning when a PR is rejected. | | **Time to approve** | The time from the first review to the time it’s approved. This represents how long engineers are spending reviewing code. If the first review is an approval, this time will be 0 as the timestamps will be the same.When you drill in to metric points below the graph, view data per PR: • PR name • Author • PR status • Review date • Approval date • Time to approve • This is the time between the review date and the approval date.**Best practice**: It is recommended to keep review time under 24 hours to maintain velocity and avoid a backlog of PRs. | | **Time to first review** | The time a PR is open to when the PR gets it’s first review (comment or approval). This represents how long PRs are waiting idol before someone starts reviewing it.When you drill in to metric points below the graph, view data per PR. • PR name • Author • PR status • Date opened • First review time • Time to first review • This is the time between the open date and the first review time.**Best practice**: It is recommended to target first review within 24 hours to ensure prompt feedback and smooth throughout. | | **Time to merge** | The time from when the PR is approved to when it’s merged.When you drill in to metric points below the graph, view data per PR: • PR name • Author • PR status • Approval date • Date closed • Time to merge • This is the time between the approval date and the date closed.**Best practice**: There is not an explicit benchmark for this metric, but note that reducing this time to under an hour boosts code velocity. Using a tool that enforces automated merges can cut down delays. | | **Time to open** | The date a PR is authored to when the PR is opened. This represents the time spent coding. Falls back to first commit date if authored date is not available.Note: This metric is not supported for [Azure DevOps](/ingesting-data-into-cortex/integrations/azuredevops) or [Bitbucket](/ingesting-data-into-cortex/integrations/bitbucket).When you drill in to metric points below the graph, view data per PR: • PR name • Author • PR status • First commit date • Date opened • Time to open • This is the time between the first commit date and the date opened.**Best practice**: There is not an explicit benchmark for this metric, but note that increasing the time to open depends on an efficient triage of work; focus on minimizing idle time before work starts. | ### Custom metrics You can view [custom metrics](/improve/eng-intelligence/custom-metrics) in Data Explorer alongside Cortex's out-of-the-box metrics, appearing in the category selected at creation. Custom metrics are displayed as raw numeric values and can be aggregated using the following operations: average, latest, max, median, min, p95, and sum. ### Entity data in table view The **Table** view supports three categories of entity data in addition to metrics. Unlike metrics, these columns aren't time series; they show the entity's current values. | Category | What it provides | | - | - | | **Custom data** | Any custom data key defined on your entities. Cortex surfaces keys from all sources: the entity descriptor (`x-cortex-custom-metadata`), the custom data API, and custom webhook integrations. Useful for columns like deployment environment or compliance status. | | **Entity definition** | Fields from the schema of a custom entity type. Use this to report on attributes that only exist on your own entity types. | | **Entity metadata** | Cortex's built-in entity attributes, such as name, tag, description, entity type, and owner. | **Example reports** You can now create the following common reports in Eng Intelligence, without CQL, and add them to saved modules and dashboards. | Report | What it provides | | - | - | | **Service inventory** | See what exists in your catalog and how it's classified, without opening each entity. Add **name**, **entity type**, and **description** from entity metadata, then add whichever custom data keys you use to classify services, such as a tier or an ID from another system of record. | | **Ownership** **audit** | Check who owns what. Add **owner** from entity metadata next to a metric like cycle time or deploy frequency to easily see who owns each entity or identify entities without owners. | | **Migration and compliance tracking** | Track a rollout across your catalog. If you record **status** as custom data, such as a migration flag or a runtime version, add that key as a column next to deployment or PR metrics. You'll see which parts of the catalog have moved and which have stalled. | Refer to [Adding entity data to table view](/improve/eng-intelligence/data-explorer#configuring-table-view) for more information. ### Scorecards **(table view only)** Table view supports Scorecard results as a metric, so a Scorecard column can sit next to delivery data in the same report. Compare a service's Scorecard score against its cycle time, or track migration progress across every entity in one view. Every Scorecard in your workspace appears in the **Metrics** window, under **Cortex (Table only) > Scorecards**. Select a Scorecard, choose a data point, then click **Select data**. | Data point | What it provides | | - | - | | **Score %** | The entity's current score as a percentage, with the points earned out of the points available, such as `67% (2/3 pts)`. | | **Level** | The level the entity has reached on the Scorecard's ladder, such as **Bronze**. Entities that haven't reached a level show **No level**. | Each column holds one data point. To show both the score and the level for the same Scorecard, add a second column and select the other data point. Columns are named for the Scorecard and the data point, such as **Git Migration (Score %)**. > [!NOTE] > > Scorecard results are evaluated per entity, so adding a Scorecard column sets **Group by** to an entity-based option. **Entity**, **Group**, **Domain**, **Entity type**, **Entity owner**, and relationship groupings stay available. Team and user groupings aren't available while a Scorecard column is in the table. > [!NOTE] > > Scorecard columns show current results rather than a time series, so the time range filter doesn't apply to them. It still applies to the metric columns in the same table. Historical Scorecard data isn't supported yet. # Data Explorer reference Source: https://docs.cortex.io/improve/eng-intelligence/data-explorer/data-explorer-reference Filter options vary depending on the metric you're viewing. For example, the **Opened PRs** metric shows version control filters, while **Story points completed** shows project management filters. For information on selecting a metric, see [Available metrics in Data Explorer](/improve/eng-intelligence/data-explorer/available-metrics-in-data-explorer#accessing-metrics-in-data-explorer). For information on accessing the filters listed below, refer to [Filtering and grouping metrics](/improve/eng-intelligence/data-explorer#step-2-filtering-and-grouping-metrics). > [!NOTE] > > Filters and 'group by' options for individual people, such as **User**, **Assignee**, **Deployer**, **Incident assignee**, and **Entity owner** when set to a user, only appear if you have the `View Eng Intelligence User Dimensions` permission. Learn more in [Custom roles](/configure/settings/managing-users/permissioning/custom-roles#available-permissions-for-custom-roles). ## Filter operators and selectors Some filters support operators and/or selectors. Select an operator/selector from the drop-down menu next to the filter name, then enter a value or values to define the range or condition. ### Numeric operators Available numeric operators: * Equals, Does not equal, >, ≥, \<, ≤, Is between, Is empty, Is not empty Numeric operators are found on the following filters: * **Version control** - Lines added, Lines deleted, Files changed, Number of comments, Commits, Cycle time, PR size * **Deployment** - Duration * **Incident** - Time to resolution * **Project management** - Story points, Time spent, Original estimate, Remaining estimate, Number of comments ### String operators Available string operators: * Is, Is not, Is empty, Is not empty, Contains, Excludes String operators are found on the following filters: * **Teams & Users** - Inherited team, User, Team, User label, User label name, Assignee, Assignee team, Assignee user label, Deployer, Incident assignee * **Entity** - Inherited domain, Inherited team owner, Domain, Entity, Entity type, Group, Entity owner * **Version control** - Label * **Deployment** - Environment, Status * **Project management** - Component, Label, Sprint, Status, Work item type > [!NOTE] > > Because they can never be empty, the following three filters have a slightly reduced set of operators \*\*(\*\*no **Is empty** / **Is not empty**): > > * **Version control** - Repository, Status > * **Project management** - Project > > One filter has its own set (**Equals**, **Does not equal**, **Is empty**, **Is not empty**): > > * **Version control** - Draft > > The **Scorecard** filter also has its own set (**Is**, **Is not**, **Is empty**, **Is not empty**): > > * **Scorecard** - Level ### Role selectors The Author/Reviewer role selector is found on the following filters: * **Version control** - User, Team, User label, User label name ## Example filter scenarios Filters are most useful when you combine them to answer a specific question. A few common examples: **Version control** * Filter **Cycle time** by **>** 3 days to find PRs that are taking longer than expected to ship. This can help you spot patterns like review bottlenecks. * Filter **Number of comments** by **Equals** 0 to find PRs that shipped with no review comments, a possible quality or risk signal. * Filter **PR size** by **>** 1,000 lines, or **Files changed** by **>** 10, to see the cycle time for your largest PRs and understand how PR size affects delivery speed. * Filter **Draft** by **Equals** true combined with **Cycle time** by **>** 7 days to catch PRs that have been sitting in draft for a long time, work that's stalled before it even reaches review. **Project management** * Filter **Story points** by **≥** 8 to surface large work items that may need to be broken down into smaller pieces. * Filter **Work item type** by **Is** "Bug" combined with **Time spent** by **>** 3 days to see which bugs are consuming the most engineering time. **Incidents** * Filter **Time to resolution** by **>** 12 hours to identify incidents where response is breaking down. **Deployments** * Filter **Duration** by **>** 30 minutes to spot patterns leading to slow deployments. * Filter **Environment** by **Is** "Staging" combined with **Status** by **Is not** "Success" to catch deployments failing in staging before they'd ever reach production. **Teams and users** * Filter **User label** by **Is** "AI User (last 7 days)" to compare cycle time or PR throughput between people using GitHub Copilot and those who aren't. * Filter **Team** with the **Reviewer** role selector to see how much review load a team is carrying across the org, not just on their own PRs. **Entity** * Filter **Entity type** by **Is** "Service" combined with **Group** by **Is** "Tier 1" to focus metrics on your most critical production services only. **Scorecards (table view only)** * Filter **Level** by **Is** "No level" to find entities that haven't reached the first level of a Scorecard yet, a quick way to see where adoption has stalled. * Filter **Level** by **Is not** "Level 3" alongside **Entity owner** to see which teams still have work left on a migration Scorecard. ## Filter definitions ### Teams and users The filters in this section focus on scoping data to specific people or teams. Available filters are dependent on the metric being viewed. | Filter | Definition | | - | - | | **Assignee** | View data for work items assigned to a specific user. | | **Assignee team** | View data for work items assigned to users belonging to a specific team. | | **Assignee user label** | View data for work items assigned to users with a specific [user label](/improve/eng-intelligence/eng-intelligence#group-by-user-label). | | **Deployer** | View data for deployments performed by a specific user. | | **Group** | View data only for entities associated with a specific [group](/ingesting-data-into-cortex/entities-overview/entities/groups). | | **Incident assignee** | View data for incidents assigned to a specific user. | | **Individual owner** | View data for metrics on entities owned by a specific user. For example, if Service X is owned by Marco, filtering by Marco only shows data for Service X even if the work was performed by someone else. | | **Inherited team** | View data for entities whose team is inherited from a parent entity in the hierarchy. | | **Team** | View data for a specific team. • For version control metrics, filters by the team of the PR author or reviewer (based on the **Version control team types** setting). • For deployment metrics, filters by the team of the deployer. • For incident metrics, filters by the team of the incident assignee. | | **Team owner** | View data for metrics on entities owned by a specific team. This only includes entities owned directly by the selected team, not its child teams. To include child teams' entities, use **Entity owner** with **Include child teams** on. | | **User** | View data authored by a specified user. | | **User label** | View data authored by users with a specific [user label](/improve/eng-intelligence/eng-intelligence#group-by-user-label). Cortex automatically creates an AI Usage label for GitHub Copilot usage with values **AI User (last 7 days)** and **Non-AI User (last 7 days)**. | | **User label name** | View data authored by users with a specific [user label](/improve/eng-intelligence/eng-intelligence#group-by-user-label) value. | ### Entity The filters in this section focus on scoping data to specific entities, entity types, or the groups they belong to. | Filter | Definition | | - | - | | **Inherited domain** | View data only for entities whose domain is inherited from a parent entity in the hierarchy. | | **Inherited team owner** | View data only for entities whose team owner is inherited from a parent entity in the hierarchy. | | **Domain** | View data only for entities belonging to a specific domain. | | **Entity** | View data only for a specific entity. | | **Entity type** | View data only for specific types of entities (such as services or teams). | | **Group** | View data only for entities associated with a specific [group](/ingesting-data-into-cortex/entities-overview/entities/groups). | | **Entity owner** | View data only for entities owned by a specific user or team. When you filter by a team, **Include child teams** is on by default, so entities owned by the team's child teams are included. Toggle it off to see only the selected team's entities. | ### **Version control** The filters in this section are specific to version control metrics and let you scope data by pull request attributes such as status, label, and repository. | Filter | Definition | | - | - | | **Label** | View data only for PRs tagged with a specific label. | | **Repository** | View data only for a specific repository. | | **Status** | View data for PRs in specified statuses. | | **Lines added** | View data for PRs with a specific number of lines added. | | **Lines deleted** | View data for PRs with a specific number of lines deleted. | | **Files changed** | View data for PRs with a specific number of files changed. | | **Number of comments** | View data for PRs with a specific number of comments. | | **Commits** | View data for PRs with a specific number of commits. | | **Draft** | View data filtered by whether PRs are drafts or not. | | **Bot generated** | View data filtered by whether PRs were generated by bots or not. | | **Cycle time** | View data for PRs within a specific cycle time range. | | **PR size** | View data for PRs within a specific size range (based on total lines of code modified). | ### **Deployments** The filters in this section are specific to deployment metrics and let you scope data by attributes such as deployment status and environment. | Filter | Definition | | - | - | | **Environment** | View data only related to a specific environment sent via the [deploys API](/api/rest/deploys). | | **Status** | View data for deployments in specified statuses. | | **Duration** | View data for deployments within a specific duration range. | ### **AI tools** There are no AI-specific filters. Only **Teams & Users** and **Entity** filters apply to AI tools metrics. ### **Project management** The filters in this section are specific to project management metrics and let you scope data by work item attributes such as status, type, sprint, and project. > [!NOTE] > > [Unique defaultJQL configurations](/ingesting-data-into-cortex/integrations/jira#set-a-default-jql-query-for-your-jira-integration) per entity aren't supported for filtering or segmenting data in Data Explorer. | Filter | Definition | | - | - | | **Component** | View data only for work items assigned to a specific component. | | **Label** | View data only for work items tagged with a specific label. | | **Project** | View data only for work items belonging to a specific project. | | **Sprint** | View data only for work items assigned to a specific sprint. | | **Status** | View data for work items in specified statuses. | | **Work item type** | View data for work items of a specific type. | | **Story points** | View data for work items with a specific story point value or range. | | **Time spent** | View data for work items with a specific amount of time logged. | | **Original estimate** | View data for work items with a specific original time estimate. | | **Remaining estimate** | View data for work items with a specific remaining time estimate. | | **Number of comments** | View data for work items with a specific number of comments. | ### **Incidents** The filters in this section are specific to incident-related metrics. > [!NOTE] > > **Team** and **user** filters are only supported for PagerDuty. | Filter | Definition | | - | - | | **Status** | View data for incidents in specified statuses. | | **Urgency** | View data for incidents in specified urgencies. | | **Time to resolution** | View data for incidents within a specific time-to-resolution range. | ### Custom metrics The filters in this section are specific to the custom metrics you created in Cortex. | Filter | Definition | | - | - | | **Inherited domain** | View data only for entities whose domain is inherited from a parent entity in the hierarchy. | | **Inherited team owner** | View data only for entities whose team owner is inherited from a parent entity in the hierarchy. | | **Domain** | View data only for entities belonging to a specific domain. | | **Entity** | View data only for a specific entity. | | **Entity type** | View data only for specific types of entities (such as services or teams). | | **Group** | View data only for entities associated with a specific [group](/ingesting-data-into-cortex/entities-overview/entities/groups). | | **Entity owner** | View data only for entities owned by a specific user or team. When you filter by a team, **Include child teams** is on by default, so entities owned by the team's child teams are included. Toggle it off to see only the selected team's entities. | ### Scorecard **(table view only)** The filter in this section applies to table view when a Scorecard column is in the report. Refer to [Scorecards in table view](/improve/eng-intelligence/data-explorer/available-metrics-in-data-explorer#scorecards-table-view-only) for more information. | Filter | Definition | | - | - | | **Level** | View data only for entities at a specific level on the Scorecard's ladder. Levels are listed by position, with the level name in parentheses, such as **Level 1 (Bronze)**. Select **No level** to find entities that haven't reached the first level yet. You can select more than one value. | ## 'Group by' definitions 'Group by' options vary depending on the metric you're viewing. For example, the **Cycle time** metric shows version control group by options, while **Story points completed** shows project management group by options. For information on selecting a metric, see [Available metrics in Data Explorer](/improve/eng-intelligence/data-explorer/available-metrics-in-data-explorer). For information on grouping metrics, refer to [Grouping metrics](/improve/eng-intelligence/data-explorer#grouping-metrics-chart-and-table-views). ### **Teams and users** The 'group by' options in this section let you segment data by specific people or teams. Available options are dependent on the metric being viewed. | Group by | Definition | | - | - | | **Team** | Group data by team. • For version control metrics, groups by the team of the PR author or reviewer (based on the **Version control team types** setting). • For deployment metrics, groups by the team of the deployer. • For incident metrics, groups by the team of the incident assignee. | | **User** | Group data by individual user. | | **User label** | Group data by [user label](/improve/eng-intelligence/eng-intelligence#group-by-user-label). | ### **Entity** The 'group by' options in this section let you segment data by entity-related attributes such as entity type, domain, or group. | Group by | Definition | | - | - | | **Entity** | Group data by individual entity. | | **Group** | Group data by the [group](/ingesting-data-into-cortex/entities-overview/entities/groups) the entity belongs to. | | **Domain** | Group data by the domain the entity belongs to. | | **Entity type** | Group data by entity type (such as services or teams). | | **Entity owner** | Group data by the user or team that owns the entity. | ### **Version control** The 'group by' options in this section are specific to version control metrics and let you segment data by pull request attributes. | Group by | Definition | | - | - | | **Repository** | Group data by repository. | | **Status** | Group data by PR status. | | **Label** | Group data by PR label. | | **Author** | Group data by PR author. | | **Reviewer** | Group data by PR reviewer. | ### **Deployments** The 'group by' options in this section are specific to deployment metrics and let you scope data by attributes such as environment. | Group by | Definition | | - | - | | **Environment** | The environment sent via the [deploys API](/api/rest/deploys). | ### **AI tools** There are no AI-specific 'group by' options. Only **Teams & Users** options apply to AI tools metrics. ### **Project management** The 'group by' options in this section are specific to project management metrics and let you segment data by project attributes. | Group by | Definition | | - | - | | **Project** | Group data by project. | | **Sprint** | Group data by sprint. | ### Incidents There are no incident-specific 'group by' options. **Teams & Users** and **Entity** options apply to incident metrics. ### Custom metrics The 'group by' options in this section are specific to the custom metrics you created in Cortex. | Group by | Definition | | - | - | | **Domain** | The domain associated with the entity. | ### Scorecards **(table view only)** There are no Scorecard-specific 'group by' options. Because Scorecard results are evaluated per entity, adding a Scorecard column limits grouping to the **Entity** options and relationship groupings. Team and user options aren't available while a Scorecard column is in the table. ### Relationships The 'group by' options in this section list the custom entity relationship types defined in your catalog. Each relationship type you've configured (for example, a service-to-repository or account-to-resource mapping) appears as its own grouping option. Select a relationship type to group and roll up metrics for entities connected through that relationship. Filtering by relationship isn't supported yet; these options are available for grouping only. # DORA Dashboard Source: https://docs.cortex.io/improve/eng-intelligence/dora-dashboard The DORA framework (DevOps Research and Assessment) is a set of metrics that help teams measure software delivery performance. Integrated into your Engineering Operations Platform, DORA metrics give engineering teams clear insights into how fast, reliable, and efficient their development practices are. This empowers teams to track progress, identify bottlenecks, and drive continuous improvement — all within the same place they manage services and deploy code. Read more about these metrics in the [dora.dev guide](https://dora.dev/guides/dora-metrics-four-keys/). Use the DORA Dashboard in Cortex to evaluate the speed and stability of your software delivery process. Visualize your team’s success across the software process and get a clear view of cycle time, deployment frequency, change failure rate, and time to resolution. ![The DORA dashboard shows graphs for the key DORA metrics.](https://mintcdn.com/cortex-290c0c42/kiI3HgqRloEyGGgk/images/dora-dashboard.jpg?fit=max\&auto=format\&n=kiI3HgqRloEyGGgk\&q=85\&s=a1903041a0c2fa1c0b1f32d161804a9f) > [!TIP] > > Looking for additional resources on enforcing DORA standards in Cortex? > > * See [Solutions: DORA Metrics](/solutions/dora) for guidance on using Cortex features to improve your DORA metrics. > * Check out the [Cortex Academy "Operationalizing DORA Metrics" course](https://academy.cortex.io/courses/cortex-solutions-operationalizing-dora-metrics), available to all Cortex customers and POVs. > * See Cortex's "Operationalizing DORA Metrics" webinar with Google Cloud's DORA program leader, Nathen Harvey, and learn about the key takeaways [in our blog](https://www.cortex.io/post/from-insight-to-impact-key-takeaways-from-our-dora-webinar-with-nathen-harvey). ## Using the DORA Dashboard To view the dashboard, click **Eng Intelligence > DORA Dashboard** in the main nav. ### Adjust the time range By default, the dashboard displays data from the last last month. To change the date range, click Last month and select a new date range. ### **Filtering the DORA Dashboard** You can filter at two levels: * **Dashboard level** - Click **Filter** at the top of the DORA Dashboard to apply a filter across all charts at once. The DORA Dashboard supports **Domain**, **Team Owner**, and **Team** as dashboard-level filters. * **Chart level** - Click **Filter** in the upper-right corner of an individual chart to apply filters for group, owner, repository, user label, and more. Chart-level filters override dashboard-level filters for that chart. ## Metric visualizations You can select a different operation for the Cycle time and Time to resolution graphs. Options include average, sum, max, min, P95, and median. Both graphs display the average by default. ### Cycle time Cycle time represents the time it takes for a single PR to go through the entire coding process. Shorter cycle times indicate a more agile team that is able to quickly respond to changing needs. **Calculation**: The time between the first commit on a PR to when the PR is merged. ![Cycle time represents the time it takes for a single PR to go through the entire coding process.](https://mintcdn.com/cortex-290c0c42/WknxdPOUKwxfFHMJ/images/cycle-time.jpg?fit=max\&auto=format\&n=WknxdPOUKwxfFHMJ\&q=85\&s=cb0a6581ccbc8f0f0f3de17d9b8da220) **Best practice**: Aim for lower cycle times to ensure a faster feedback loop and reduced context switching. Rather than benchmarking the overall cycle time, set benchmarks for the individual parts of the cycle (time to open, time to approve, time to first review, time to merge). Note: This metric is not supported for [Azure DevOps](/ingesting-data-into-cortex/integrations/azuredevops) or [Bitbucket](/ingesting-data-into-cortex/integrations/bitbucket). ### Deployment frequency Deployment frequency measures how often your team successfully releases code to production, serving as a key indicator of your delivery velocity and operational maturity. This DORA metric reflects your team's ability to deliver value continuously and respond quickly to market demands. **Calculation**: The number of deployments over a given period of time. ![Deployment frequency represents how often code is deployed to a production environment](https://mintcdn.com/cortex-290c0c42/WknxdPOUKwxfFHMJ/images/deployment-frequency.jpg?fit=max\&auto=format\&n=WknxdPOUKwxfFHMJ\&q=85\&s=951414b615525616f51d5138089550f1) **Best practice**: Depending on your organization, a successful benchmark could be multiple deployments per day or per week. ### Change failure rate Change failure rate measures the percentage of deployments that result in production failures, serving as a critical indicator of deployment stability and code quality. This DORA metric reveals how often your releases introduce bugs, outages, or performance issues that impact users. **Calculation**: `Number of rollbacks / number of deployments created`. ![The change failure rate graph shows the percentage of deployments that result in a failure in production.](https://mintcdn.com/cortex-290c0c42/kiI3HgqRloEyGGgk/images/dora-change-failure.jpg?fit=max\&auto=format\&n=kiI3HgqRloEyGGgk\&q=85\&s=384de548d1c8e058423a12ac6c3c38fb) **Best practice**: Aim for a failure rate less than 15%. ### Time to resolution (MTTR) Time to resolution measures how quickly your team recovers from production failures, reflecting your incident response capabilities and system resilience. Also known as mean time to recovery (MTTR), this metric indicates how well-prepared your team is to handle inevitable production issues. **Calculation**: `Incident resolution time - incident opened time`. ![The time to resolution graph shows how long it takes a team to recover from failure in production.](https://mintcdn.com/cortex-290c0c42/kiI3HgqRloEyGGgk/images/dora-mttr.jpg?fit=max\&auto=format\&n=kiI3HgqRloEyGGgk\&q=85\&s=64dd60df7fc09089ca831d7a10140dc1) **Best practice**: This benchmark may differ depending on how critical a system is. For less critical systems, aim for a measure of less than 1 day. For critical systems, aim for under 1 hour. # Velocity Dashboard Source: https://docs.cortex.io/improve/eng-intelligence/velocity-dashboard The Velocity Dashboard provides a one-stop-shop into your software development lifecycle helping you and your teams understand any bottlenecks in your process. Get a clear view of PR cycle time to identify bottlenecks and spot inefficiencies, compare pull request size against commit activity, and visualize your team’s success rate across the entire review process — all in one place. ![](https://mintlify.s3.us-west-1.amazonaws.com/cortex-290c0c42/images/Screenshot%202025-07-23%20at%202.56.04%E2%80%AFPM.png) ## Using the Velocity Dashboard To view the dashboard, click **Eng Intelligence > Velocity Dashboard** in the main nav. ### Adjust the time range By default, the dashboard displays data from the last 7 days. To change the date range, click **Last 7 days** and select a new date. ### Apply a filter option You can apply filters across for team, owner, repository, user label, and more to narrow down the set of data you are reviewing. To select filters, click **Filter** in the upper right corner of a graph. ### Drill down For each metric, click on the card to drill down into the data for further analysis. After clicking into the card, you can segment the data and drill down further to view a list of data points: ![Click a metric card to see a visual and data that can be segmented. Drill further into that data to get a list of data points.](https://mintcdn.com/cortex-290c0c42/kiI3HgqRloEyGGgk/images/drill-down-diagram.jpg?fit=max\&auto=format\&n=kiI3HgqRloEyGGgk\&q=85\&s=633b7174415dff574644ac6ee483e687) ## Cycle time breakdown Cycle time measures the complete journey of a pull request from first commit to merge into your main branch. Understanding this end-to-end process is crucial for identifying bottlenecks and optimizing your development workflow. Note: Cycle Time and Time to Open metrics are not supported for [Azure DevOps](/ingesting-data-into-cortex/integrations/azuredevops) or [Bitbucket](/ingesting-data-into-cortex/integrations/bitbucket). The four stages of cycle time: * **Time to open:** Development phase: First commit to PR creation * **Best practice**: There is not an explicit industry benchmark for this metric, but note that increasing the time to open depends on an efficient triage of work; focus on minimizing idle time before work starts. * **Time to approve:** Review process: First review to final approval * **Best practice**: It is recommended to keep review time under 24 hours to maintain velocity and avoid a backlog of PRs. * **Time to first review:** Waiting period: PR opened to initial reviewer engagement * **Best practice**: It is recommended to target first review within 24 hours to ensure prompt feedback and smooth throughout. * **Time to merge:** Merge process: Approval to successful merge * **Best practice**: There is not an explicit benchmark for this metric, but note that reducing this time to under an hour boosts code velocity. Using a tool that enforces automated merges can cut down delays. ![](https://mintlify.s3.us-west-1.amazonaws.com/cortex-290c0c42/images/Screenshot%202025-07-23%20at%203.05.09%E2%80%AFPM.png) ### Key insight Most teams discover that one of these four areas makes up 50-60% of their overall cycle time, providing a clear picture of a focus area to improve overall velocity. ### Cycle time best practices * Set SLA targets for each stage (e.g., first review within 1 business day) * Implement automated code review assignments to eliminate reviewer uncertainty * Use draft PRs for work-in-progress to separate development time from review time * Track P95 metrics to identify and address outlier PRs that skew team performance ### Visualization options Choose from multiple statistical views (average, sum, max, min, P95, median) to analyze your data. The default average view provides a balanced perspective, while P95 highlights outliers that might indicate systemic issues. ## Cycle time x PR size Pull request size directly impacts development velocity. Larger PRs consistently correlate with longer cycle times across every stage of the development process - from initial review to final merge. This visualization helps you understand how PR size affects efficiency throughout your development lifecycle. Compare your pull request size to: * Time to open * Time to first review * Time to approve * Time to merge * Overall cycle time ![](https://mintlify.s3.us-west-1.amazonaws.com/cortex-290c0c42/images/Screenshot%202025-07-23%20at%203.24.17%E2%80%AFPM.png) ### Key insight Smaller PRs move faster. They're easier to review, less likely to introduce conflicts, and require fewer revision cycles. Teams that maintain smaller, focused PRs typically see 2-3x faster cycle times and higher code quality. ### PR size best practices Aim for PRs under 400 lines of code. Break larger features into smaller, logical chunks that can be reviewed and merged independently. ### Visualization options Outliers are excluded by default. To include them, toggle on the **Show outliers** option. ## PR success rate PR success rate measures the percentage of pull requests that successfully make it from creation to merge, providing critical insight into development efficiency and process waste. A high success rate indicates focused development work, while a low rate suggests potential issues with planning, scope creep, or unclear requirements. ![](https://mintlify.s3.us-west-1.amazonaws.com/cortex-290c0c42/images/Screenshot%202025-07-23%20at%203.27.14%E2%80%AFPM.png) ### Key insights A sudden drop in success rate often correlates with rushed feature development, unclear requirements, or experimental work that should happen in separate branches. High-performing teams maintain consistent success rates even during periods of increased PR volume. ### PR success best practices * Target a PR success rate above 80% for optimal efficiency * Review closed (unmerged) PRs weekly to identify patterns and root causes * Implement clearer definition-of-done criteria before starting development * Use draft PRs for experimental work to separate exploration from production-ready code * Track success rate alongside cycle time - both metrics together reveal process health * Consider feature flags for risky changes instead of abandoning PRs ### Visualization options Switch between viewing open, closed or merged PRs against success rate. # Initiatives and Action items Source: https://docs.cortex.io/improve/initiatives Drive action on the standards set in Scorecards While [Scorecards](/standardize/scorecards) allow you to set benchmarks, Initiatives help you set targeted goals to meet specific standards within a specified deadline. Set a clear goal (e.g., "90% of services are production-ready by Q3"), attach a deadline, assign owners, and Cortex will automatically notify users and track progress for you. Initiatives offer a streamlined view into the most critical tasks, improving not just the efficiency of your team members, but the accountability of your teams as well. See [examples of Initiatives](/improve/initiatives#initiative-examples) or [ask Cortex MCP](/improve/initiatives#using-cortex-mcp-for-initiative-ideas) to help you get started. > [!TIP] > > Looking for a quick introduction to Initiatives? Check out the [Cortex Academy "Intro to Initiatives" course](https://academy.cortex.io/courses/introduction-to-initiatives), available to all Cortex customers and POVs. ### Using Cortex MCP for Initiative ideas Not sure where to start? Use [Cortex MCP](/get-started/cortex-ai-assistant/mcp) to ask questions in natural language and receive detailed responses that take your environment into account. For example, you might use the following prompt: *I want to run an initiative to migrate our company to using GitHub Actions. Help me figure out how to do this in Cortex.* * The MCP will respond with a detailed plan, an implementation timeline, best practices, and a list of next steps. See [Cortex MCP](/get-started/cortex-ai-assistant/mcp) for configuration instructions. ## Initiatives overview In the video below, learn how [Scorecards](/standardize/scorecards), [Initiatives](/improve/initiatives), and [Reports](/improve/reports) can be used together to drive business goals. [YouTube video player](https://www.youtube.com/embed/oIWbMlK7Qh4) ## Create an initiative ### Prerequisites Before getting started: * You should have already [created a Scorecard](/standardize/scorecards) or have an existing Scorecard in mind that you plan to launch an Initiative on; Initiatives are targeted goals tied to a Scorecard. The Scorecard must be published and not in draft mode. * You must have the `Edit Initiatives` permission. * [Configure notifications](/configure/settings/notifications) for Initiatives to ensure that the right people are alerted to new Initiatives and approaching deadlines. Learn more about notification types below. #### Initiative notifications Expand the tile below to learn more about the different types of Initiative notifications and to ensure you are configuring notifications to be sent to the expected recipient. It is possible to send notifications to entity owners, to team entity owners, or only to the communications channel associated with the entity. > **Expand to learn more about Initiative notifications** > > Users with the `Configure workspace notification settings` permission can configure notifications for Initiatives under [Settings > Notifications](https://app.getcortexapp.com/admin/settings/notifications). These global workspace settings override the [individual toggle that you can enable during Initiative creation](/improve/initiatives#step-1-configure-the-initiatives-basic-details); if someone has disabled the workspace notification option for "Initiative custom scheduled reminders" and "Initiative reminders," then you will not be able to trigger notifications for Initiative reminders via the toggle during creation of the Initiative. > > Also note that users must opt in to Initiative-related notifications in their [personal notification settings](/configure/settings/notifications#adjusting-your-personal-notification-subscriptions). > > Where a notification is sent depends on the type of notification you enable, as described below. > > **Initiative creation notifications** > > The "Enable notifications" toggle that appears during Initiative creation does not apply to Initiative creation notifications; it only applies to Custom Initiative reminders. The "Initiative creation" notification is configured under [Settings > Notifications](https://app.getcortexapp.com/admin/settings/notifications). > > When an entity is included in a newly-created Initiative (not in draft format), you can configure notifications to be sent based on: > > * Users who own the entity: Enable **Users > Initiative creation**. > * For the individual user who owns the entity, notifications will be sent to them when an Initiative is launched via email, Slack, or MS Teams, depending on your notification settings.) > * Team members who own the entity: Enable **Team-based > Initiative creation.** > * For the team who owns the entity, notifications will be sent to the team members when an Initiative is launched (via email, Slack, or MS Teams, depending on your notification settings.) > * The entity's associated Slack channel: Enable **Entity-based > Initiative creation**. > * A notification will go to the Slack channel associated with the entity. > > **Initiative reminder notifications** > > If "Initiative reminder" notifications are enabled in [Settings > Notifications](https://app.getcortexapp.com/admin/settings/notifications), users will receive reminders of pending action items 7 days and 1 day before the due date. This date will also be reflected in action items on the [engineering homepage](/streamline/homepage). > > You can configure reminders for approaching deadlines based on: > > * Users who own an entity that is included in the Initiative: Enable **Users > Initiative reminders**. > * When an entity is part of an Initiative, for the individual user who owns the entity, notifications will be sent to them when an Initiative is launched. Notifications can be sent via email, Slack, or MS Teams, depending on your notification settings. > * Team members who own the entity: Enable **Team-based > Initiative reminders.** > * When an entity is part of an Initiative, for the team who owns the entity, notifications will be sent to the team members when an Initiative is launched (via email, Slack, or MS Teams, depending on your notification settings.) > * The entity's associated Slack channel: Enable **Entity-based > Initiative reminders**. > * When an entity is part of an Initiative, a notification will go to the Slack channel associated with the entity. > > **Custom Initiative reminder notifications** > > While configuring an Initiative, you have the option of setting of custom timeframes for Initiative reminders: > > ![](https://mintcdn.com/cortex-290c0c42/WknxdPOUKwxfFHMJ/images/custom-initiative-reminders.jpg?fit=max\&auto=format\&n=WknxdPOUKwxfFHMJ\&q=85\&s=61b3b80f066c3bc198fd1c53aae31573) > > If you enable a custom notification during the creation of an Initiative, you must also have the global workspace notification for "Initiative custom scheduled reminders" enabled. > > When these notification settings are enabled: > > * If a user owns an entity that is a part of the Initiative, they will receive progress notifications at the interval you specified while configuring the Initiative (as shown in the screen shot above). ### Step 1: Configure the Initiative's basic details 1. Click **Create Initiative** in the upper right corner of the Initiatives page. ![](https://mintcdn.com/cortex-290c0c42/WknxdPOUKwxfFHMJ/images/create-initiative-scorecard.jpg?fit=max\&auto=format\&n=WknxdPOUKwxfFHMJ\&q=85\&s=0d174b221345f7fb6c8c4d3b41e4921c) 2. Choose the Scorecard that the Initiative is attached to. 3. Start configuring the form: * **Name**: Add a descriptive name, e.g., `Improve DORA metrics by Q3`. * **Description**: Enter a description to help make the Initiative's goal clear. * **Notifications**: Optionally click the toggle to enable progress notifications for the Initiative's due date. These notifications are sent to users who own an entity that is part of this Initiative if the entity has not yet completed the goal. The first reminder notification will send the next time that 3 p.m. UTC is reached after the notification schedule has been created. * Configure how often to send progress notifications. You can also designate one or more reply-to email addresses. * Note that [global workspace settings](/configure/settings/notifications#setting-notifications-for-the-entire-workspace) override this option; if all Initiative reminder notifications are disabled globally, then this setting will not trigger reminder notifications. ![](https://mintcdn.com/cortex-290c0c42/4tRxSDOxhMkPeY0E/images/initiative-notifications.jpg?fit=max\&auto=format\&n=4tRxSDOxhMkPeY0E\&q=85\&s=d18765aff4bf28a13afbbe8cf667a623) > [!TIP] > > Progress notifications can enhance both short-term and long-term Initiatives. For example: > > * Initiative owners can set daily progress notifications for short-term Initiatives so users have clear goals each day for completing time-sensitive action items. > * Initiative owners can set bi-weekly or monthly progress notifications for an ongoing, long-term Initiative so users continue to make progress on action items over time. ### Step 2: Define the Initiative's goal 1. In the Initiative creation form under **Define goal,** select the level or rules to prioritize. The levels and rules available are based on the associated Scorecard. ![](https://mintcdn.com/cortex-290c0c42/4tRxSDOxhMkPeY0E/images/level-goal.jpg?fit=max\&auto=format\&n=4tRxSDOxhMkPeY0E\&q=85\&s=9bba80af7d4a045b43a1a311a1e8557e) * **Scorecard level**: To satisfy level-based Initiative, owners must meet all of the rules for a level. This is a good option if your goal is to bump all entities up to a similar level on your ladder. * For example, to get all entities into a production-ready state, you might use a level-based Initiative to motivate your team to configure PagerDuty and add runbooks for every entity they own by the end of the quarter. * **Rules**: Choose this option to focus on specific rules. This may be a better option if you have targeted goals that your team needs to achieve. * For example, if most of your entities are already in a production-ready state, you might only need PagerDuty to be set up for some of your entities. 2. Under **Due date**, select a deadline for the Initiative. * If notifications are enabled, users will receive reminders of pending action items 7 days and 1 day before the due date. This date will also be reflected in action items on the [dev homepage](/streamline/homepage). ### Step 3: Finish the Initiative configuration 1. Under **Apply to specific entities**, add one or more entity types that this Initiative should apply to. If left blank, it will apply to all entities. 2. Optionally, click to expand **Advanced options** and further refine which entities this Initiative applies to. You can include or exclude groups, or add a CQL expression. 3. Choose whether to keep your Initiative in draft form, visible only to users with the `Edit Initiatives` permission. * To keep it in draft form, enable the toggle next to **Save as draft**. * Initiatives in draft status will not appear on entity pages or in actions on the [dev homepage](/streamline/homepage), and will not trigger notifications. 4. Click **Create Initiative**. When you create an Initiative, all of the owners with outstanding action items will be notified by Cortex. Users who own an entity that's already met the rule or achieved the action item will not be notified. Those who own multiple entities will receive a notification outlining any entities with an outstanding action item. The new Initiative will also appear on the [Initiatives page](https://app.getcortexapp.com/admin/initiatives). ## Edit Initiatives You must have the `Edit Initiatives` permission. To edit an Initiative: 1. Navigate to an Initiative page then click **Edit** in the upper right corner. ![](https://mintcdn.com/cortex-290c0c42/kiI3HgqRloEyGGgk/images/edit-initiative.jpg?fit=max\&auto=format\&n=kiI3HgqRloEyGGgk\&q=85\&s=8201ebf073e743c6a45e2c7132a498c0) 2. Make any desired changes. 3. At the bottom of the page, click **Save Initiative**. ## View Initiatives You must have the `View Initiatives` permission. > **View the Initiatives list** > > **View the Initiatives list** > > To view Initiatives, navigate to [**Scorecards > Initiatives**](https://app.getcortexapp.com/admin/initiatives) in the main nav. > > ![Click Initiatives in the main nav.](https://mintcdn.com/cortex-290c0c42/4tRxSDOxhMkPeY0E/images/initiatives.jpg?fit=max\&auto=format\&n=4tRxSDOxhMkPeY0E\&q=85\&s=064b5d98245acf107cc14099aeb4d207) > > By default, the page displays a list of active Initiatives at your organization, including their description, associated Scorecard, progress level, and deadline. To view expired Initiatives, click the **Expired** tab. > **View individual Initiatives** > > **View individual Initiatives** > > From the Initiatives list, click into an Initiative to view its details page. > > ![The Initiatives page displays failing entities by default.](https://mintcdn.com/cortex-290c0c42/4tRxSDOxhMkPeY0E/images/initiative.jpg?fit=max\&auto=format\&n=4tRxSDOxhMkPeY0E\&q=85\&s=1345740a88f97793b9658c1c9ef5848a) > > By default, this page will open to the **Failing** tab, where you can see each entity's progress in the Initiative. Each row displays how many rules out of the total are passing for that entity. Click an entity to expand the view and see which rules are failing: > > ![Click an entity to view its failing rules.](https://mintcdn.com/cortex-290c0c42/OnaYqLHqq-U_XM2R/images/expand-entity-initiative.jpg?fit=max\&auto=format\&n=OnaYqLHqq-U_XM2R\&q=85\&s=863fbfdc09dfd74d5399f0ac7c4646d5) > > Once entities have completed all action items, they will appear under the **Passing** tab. > **View your Initiative action items** > > **View Initiative action items** > > You can find all outstanding tasks for Initiatives related to entities you own on the [Engineering homepage](/streamline/homepage) in **Action items**: > > ![Click Action items on the dev homepage.](https://mintlify.s3.us-west-1.amazonaws.com/cortex-290c0c42/images/action-items%20%281%29.jpg) > > This section lists the entity, the failing rule, the associated Scorecard or Initiative, the due date (if it's linked to an Initiative), and the priority based on Scorecard level. > > By default, action items are sorted by priority level. Tasks with deadlines are sourced from Initiatives; those without deadlines are sourced from failing Scorecard rules. > > **Filter and sort action items** > > ![Filter and sort in the upper right side of the Action Items section.](https://mintlify.s3.us-west-1.amazonaws.com/cortex-290c0c42/images/filter-action-items%20%281%29.jpg) > > * In the upper right corner of the list, click **Priority** to choose a different sorting method. You can select priority, name, source, or rule. > > * To filter by Scorecard, Initiative, or group, click **Filter**. > > * To group actions by entity, click Display then enable the toggle next to **Group by entity**. > > > [!TIP] > > > > Grouping by entity gives a clearer view of how many tasks are associated with each entity, giving developers an easy target for improvements. ## Initiative examples See the examples below to learn common ways our customers drive organizational change with Initiatives. > **Ensure services have active on-call rotations in 30 days** > > Your Scorecard may have a rule that measures whether each service has an on-call rotation configured through PagerDuty. > > To make sure that all services actually have active on-call rotations within 30 days, you could create an Initiative with a due date in 30 days. > > * Entity owners will see the Initiative tasks listed on their [engineering homepage](/streamline/homepage) under "Tasks." > * If [notifications are enabled](/improve/initiatives#expand-to-learn-more-about-initiative-notifications), reminders will be sent to Slack or MS Teams when the Initiative is due in 7 days and again when the Initiative is due in 1 day. > **Complete 'Bronze' level for Incident Preparedness in the next 2 weeks** > > While viewing your Incident Preparedness Scorecard, you notice that the Bronze level rules have not yet been met for many entities: > > ![](https://mintcdn.com/cortex-290c0c42/4tRxSDOxhMkPeY0E/images/incident-initiative-example.jpg?fit=max\&auto=format\&n=4tRxSDOxhMkPeY0E\&q=85\&s=d0b68e02130ffbaff725e26ae19d6067) > > To encourage your team to reach the baseline standards for their entities, you decide to create an Initiative. It includes: > > * A goal of completing the Bronze level items in your Scorecard by the next two weeks > * Notifications enabled, with progress notifications configured to be sent daily to users > > ![](https://mintcdn.com/cortex-290c0c42/4tRxSDOxhMkPeY0E/images/incident-prepared-initiative.jpg?fit=max\&auto=format\&n=4tRxSDOxhMkPeY0E\&q=85\&s=8c1b42e5c86afe5657767ab4f0ea12b6) > **Ensure services have CI workflow for migration process by end of month** > > Your organization is migrating to GitHub Actions to standardize CI/CD and get better visibility into engineering processes. You have already created a Scorecard to track the migration process. It includes rules that check whether repositories have a `.github/workflows/` file or not, whether they have a CI workflow, whether they use dependency caching, and more. > > To motivate your teams to get the migration finished more quickly, you create an Initiative connected to your migration Scorecard. The Initiative is for the rule "Has CI workflow": > > * **Initiative name**: Ensure services have CI workflow by November > * **Description**: To move our migration forward, let's work toward ensuring services have a CI workflow this month. > * Notifications are enabled to ensure that the entity owners are alerted of this action item. In the example screen shot below,, the progress notifications are configured to be sent once a day. > > ![Basic configurations are in place for an Initiative called 'Ensure services have CI workflow by November.'](https://mintcdn.com/cortex-290c0c42/wjT-J8PNs9MwpcFs/images/migration-init-example.jpg?fit=max\&auto=format\&n=wjT-J8PNs9MwpcFs\&q=85\&s=0315131a19faed5b66747501551549e3) > * **Define goal**: The goal is set to the "Has CI Workflow" rule and has a due date of November 1. > > ![The goal is set to the 'Has CI Workflow' rule and has a due date of November 1](https://mintcdn.com/cortex-290c0c42/wjT-J8PNs9MwpcFs/images/migration-init-goal-example.jpg?fit=max\&auto=format\&n=wjT-J8PNs9MwpcFs\&q=85\&s=a086c364370044b9a3fa4c96791f8989) > **Accelerate migration to K8s** > > Cortex customer LetsGetCheck cut their Kubernetes migration timeline from 24 months down to 16 months by targeting goals with Initiatives. [Read the full case study here](https://www.cortex.io/case-studies/letsgetchecked). > > If you are migrating to Kubernetes, you might follow a process similar to the following example: > > 1. Launch a Scorecard to measure Kubernetes readiness. > * It might include rules such as "Has a Helm chart," "Uses supported base image," "Runs in cluster." > 2. Several months in to your migration, you notice that the team isn't making progress in the timeframe you expected. They have completed most of the Bronze and Silver level rules in the Scorecard, but many entities have not achieved the Gold level rules yet. > 3. You decide to launch an Initiative connected to the Scorecard to ensure that you meet your business goals of being migrated by the end of the fiscal year: > * **Title**: Accelerate Kubernetes migration > * **Description**: Track and accelerate migration of services to Kubernetes > * **Define goal**: Complete the Gold level of the Kubernetes Readiness Scorecard, due in 2 months. > * This effectively asks your developers to accomplish all of the Scorecard's rules by the deadline you specify. > * **Notifications**: Enable notifications and send progress updates every week. > 4. If an entity has not achieved the rules in the Gold level of the Scorecard, then that entity's owner will see action items listed on their [engineering homepage](/streamline/homepage) and they will automatically receive a weekly progress update from the Initiative. > **Ensure continuous SOC-2 compliance** > > If you are working toward organizational SOC-2 compliance, you might follow a process similar to this example: > > 1. Launch a SOC-2 compliance Scorecard with rules reflecting control requirements. > * Cortex has a pre-built SOC-2 compliance Scorecard template available in-app. > 2. Attach a SOC-2 readiness Initiative to the Scorecard. In the Initiative, require the Gold level rules of your Scorecard to be completed for every service by the end of the quarter. > 3. After completing the SOC-2 audit, reuse the same Scorecard and Initiative frameworks for the next cycle. > * This helps you stay prepared and avoid the last-minute scramble every year. > **Ensure AWS resources are off EOL versions by specified date** > > You can use an Initiative to manage and drive an AWS End-of-Life (EOL) migration by combining resource cataloging, Scorecards, and Initiative tracking. Here’s how you would approach it: > > 1. Ensure all relevant AWS resources (such as RDS, Lambda, ElastiCache, etc.) are imported into your resource catalog. Learn about [importing AWS entities here](/ingesting-data-into-cortex/integrations/aws). > 2. Set up a Scorecard to automatically audit and score your AWS resources for EOL risk. This helps you quickly identify which resources need to be updated or migrated. > 3. Create an Initiative in Cortex linked to your EOL scorecard. Set a clear target for the title (e.g., “All AWS resources must be off EOL versions by \[date]”). > * If a resource is not off the EOL version, then that resource's owner will see this as an action item listed on their [engineering homepage](/streamline/homepage). If you enabled notifications, they will receive reminders as the deadline approaches. > 4. Use [reports](/improve/reports) to monitor progress in real time. Owners of non-compliant resources will receive notifications and reminders, and you can track which teams or services are lagging behind. This ensures accountability and helps drive the migration to completion.\\ > **Manage package upgrades quickly** > > Cortex Initiatives provide a structured, automated, and transparent way to manage package upgrades, ensuring visibility, accountability, and timely completion across all affected services. For example, if you need to migrate everyone from version 1 to version 1.1 of an internal library, you can set up an Initiative to track and drive the upgrade to completion: > > 1. Launch a Scorecard or CQL report: Identify which services are on the old version and which have already upgraded. This allows you to automatically audit the state of package usage across your organization. > 2. Launch an Initiative on the Scorecard with a name like "100% of services must be on version 1.1 by end of quarter." > * If an entity has not achieved the rules specified in the Initiative, then that entity's owner will see action items listed on their [engineering homepage](/streamline/homepage) reminding them to get their service upgraded. > 3. Monitor progress in real time via [reports](/improve/reports), where you can track which teams or services are lagging behind. This ensures accountability and helps drive the migration to completion. ## Troubleshooting and FAQ #### Why didn't I receive a notification for an Initiative? This can happen if your Initiative was created in draft format. When the Initiative is published, it will start to trigger [notifications](/configure/settings/notifications). You should also ensure that you enabled the right notification type for your use case. For example, if you only enable the Entity-based option for Initiative reminders, then notifications will go only to the channel associated with the entity; the entity owners would not necessarily be notified. Learn more about [Initiative notifications](/improve/initiatives#initiative-notifications) above. # Creating issues based on Initiatives Source: https://docs.cortex.io/improve/initiatives/issue-config By integrating your issue tracking tools with Cortex, you can take Initiatives and action items to the next level. Through integrations with tools like Jira, ClickUp, Azure DevOps, and GitHub, you can automatically create issues for outstanding action items based on Initiatives in Cortex. ## How to create issues based on Initiatives To automatically create issues based on Initiatives, you’ll need to set up an issue configuration. An issue configuration combines a set of filters and a configuration for an issue tracking tool integration. For example, an issue configuration could comprise the entity types that the config applies to and the Jira projects the issues should go into. This flexibility allows managers to be sure that issues for their teams end up in the right place. ### Prerequisites An integration with an issue tracking tool (Jira, ClickUp, Azure DevOps, or GitHub) must be set up before you can create an issue configuration. ### Create an issue configuration When using issue configurations, think about what makes the most sense for your team. You can create just one configuration for an Initiative, so that all Cortex-created issues are directed to a single project for team members to pick up from there. There’s also no limit to the number of configs you can add. By setting up multiple configurations, you can automate which project each set of issues belongs to, minimizing the manual work involved in managing issues. Expand the tabs below for instructions on creating an issue for each issue tracking tool option. > **Azure DevOps** > > 1. Navigate to the Initiative you want to work with. Under its **Issue configs tab**, click **Create issue config**. > > ![](https://mintcdn.com/cortex-290c0c42/4tRxSDOxhMkPeY0E/images/issue-config-tab.jpg?fit=max\&auto=format\&n=4tRxSDOxhMkPeY0E\&q=85\&s=1acba909067307c831756b3d900dadb3) > > 2\. Configure the issue form: > > * **Issue config name**: Enter a descriptive name for the issue configuration. > * The name can help users understand which team the issue belongs to and the project the issues should be assigned to. > * **Integration**: Select Azure DevOps. > * **Azure DevOps configuration:** Select the Azure DevOps configuration alias you want to use if you have multiple in your workspace. > * **Work item type**: Select a work item type. > * Azure DevOps [work item types](https://learn.microsoft.com/en-us/azure/devops/boards/work-items/about-work-items?view=azure-devops\&tabs=agile-process) are designed to distinguish and categorize different types of work to introduce more structure into the process. > * **Sub-item type**: Select a sub-item type. > * Note that the sub-item type can only apply to child issues. > * Additional optional fields differ depending on the issue type and sub-item type selected and your Azure DevOps instance requirements for new issues. > * **Apply to specific entities**: Optionally choose to include or exclude specific entity types. By default, the issue will apply to all entities in an Initiative. > * **Advanced options**: Further refine entity selecting by applying filters for groups or a CQL expression. > > 3. Click **Create issue config**. > **ClickUp** > > Note that additional fields differ depending on your ClickUp instance requirements for new issues. If fields are required in ClickUp, you must populate these fields for your issue configuration. > > 1. Navigate to the Initiative you want to work with. Under its **Issue configs tab**, click **Create issue config**. > > ![](https://mintcdn.com/cortex-290c0c42/4tRxSDOxhMkPeY0E/images/issue-config-tab.jpg?fit=max\&auto=format\&n=4tRxSDOxhMkPeY0E\&q=85\&s=1acba909067307c831756b3d900dadb3) > > 2\. Configure the issue form: > > * **Issue config name**: Enter a descriptive name for the issue configuration. > * The name can help users understand which team the issue belongs to and the project the issues should be assigned to. > * **Integration**: Select ClickUp. > * **Inherit project from entity YAML**: When this toggle is enabled, the issue will use the ClickUp list defined in a given entity's YAML. > * **Default space**: Choose a space where the Cortex-created issues will be directed. > * **List**: Select a ClickUp list. > * **Tag**: Select a tag. > * **Priority**: Select a priority for this issue. > * **Add entity tag**: Toggle this setting on to add an entity tag to the issue. > * **Apply to specific entities**: Optionally choose to include or exclude specific entity types. By default, the issue will apply to all entities in an Initiative. > * **Advanced options**: Further refine entity selecting by applying filters for groups or a CQL expression. > > 3. Click **Create issue config**. > **GitHub** > > 1. Navigate to the Initiative you want to work with. Under its **Issue configs tab**, click **Create issue config**. > > ![](https://mintcdn.com/cortex-290c0c42/4tRxSDOxhMkPeY0E/images/issue-config-tab.jpg?fit=max\&auto=format\&n=4tRxSDOxhMkPeY0E\&q=85\&s=1acba909067307c831756b3d900dadb3) > > 2\. Configure the issue form: > > 1. **Name**: Enter a descriptive name for the issue configuration. > > * The name can help users understand which team the issue belongs to and the project the issues should be assigned to. **Use issue defined in entity yaml**: When this toggle is enabled, the issue will use the GitHub issue defined in a given entity's YAML. > > 2. **Integration**: Select GitHub. > > 3. **Labels**: Select or create a label. > > 4. **Apply to specific entities**: Optionally choose to include or exclude specific entity types. By default, the issue will apply to all entities in an Initiative. > > * Advanced options: Further refine entity selecting by applying filters for groups or a CQL expression. > > 3. Click **Create issue config**. > **Jira** > > 1. Navigate to the Initiative you want to work with. Under its **Issue configs tab**, click **Create issue config**. > > ![](https://mintcdn.com/cortex-290c0c42/4tRxSDOxhMkPeY0E/images/issue-config-tab.jpg?fit=max\&auto=format\&n=4tRxSDOxhMkPeY0E\&q=85\&s=1acba909067307c831756b3d900dadb3) > > 2\. Configure the issue form: > > * **Issue config name**: Enter a descriptive name for the issue configuration. > * The name can help users understand which team the issue belongs to and the project the issues should be assigned to. > * **Integration**: Select `Jira`. > * **Inherit project from entity YAML**: When this toggle is enabled, the issue will use the Jira project defined in a given entity's YAML. > * You will be able to select a fallback default project, and choose the issue type. If that issue type does not exist in the project defined on the entity's YAML, Cortex will fallback to a 'task' type. > * **Default Jira project**: Select the Jira project where Cortex-created issues will be directed. > * **Jira configuration:** Select a Jira configuration alias. > * If you have multiple Jira integrations in your workspace, select the one you want to set up the issue config in. > * **Issue type**: Select a Jira issue type. > * Jira [issue types](https://support.atlassian.com/jira-cloud-administration/docs/what-are-issue-types/) are designed to distinguish and categorize different types of work to introduce more structure into the process. > * Additional optional fields differ depending on the issue type selected and your Jira instance requirements for new issues. If fields are required in Jira, you must populate these fields for your issue configuration. > * **Subtask issue type** - Choose whether Cortex creates a Jira subtask for each action item in the Initiative. > * **Create a subtask for each action item** - When this toggle is enabled, Cortex creates a parent issue plus one subtask per action item. Select a **Subtask issue type** for those subtasks. > * The subtask issue type only applies to child issues. > * Additional optional fields differ depending on the subtask issue type you select and your Jira instance's requirements for new issues. If fields are required in Jira, you must populate them for your issue configuration. > * When this toggle is disabled, Cortex creates only the parent issue and adds the action items to its description. This is useful when an Initiative has a single rule, where a subtask would duplicate the parent issue. > * **Apply to specific entities**: Optionally choose to include or exclude specific entity types. By default, the issue will apply to all entities in an Initiative. > * **Advanced options**: Further refine entity selecting by applying filters for groups or a CQL expression. > > 3. Click **Create issue config**.\\ ### Automatic issue creation in your issue tracking tool After saving the issue configuration, Cortex will automatically create a corresponding issue in your issue tracking tool for you. Cortex will create a single parent task for each entity, and each failing rule will be created as a subtask. This makes it easy for you to track the aggregate data while maintaining visibility into all failing rules. ## Closing and reopening issues Once an entity passes an action item, Cortex will attempt to close out the corresponding issue. If Cortex is unable to close a issue, a comment will be left notifying you that an action item is now **Passing**. Cortex will go through this process any time a Scorecard is refreshed and rules are reevaluated. If a new rule is added to an Initiative, a new issue will be created opened based on the configuration you’ve defined. Cortex will also reopen issues for existing configurations if a passing action item reverts to failure, including issues that have been manually closed by a user. ## Viewing and editing issue configurations You can modify or delete your configurations. To edit an existing configuration: 1. Navigate to the Initiative and click the **Issue configs** tab. 2. On the right side of the issue config, click the 3 dots icon, then click **Edit config**. ![Next to an issue config, click the 3 dots then select 'Edit config.'](https://mintcdn.com/cortex-290c0c42/kiI3HgqRloEyGGgk/images/edit-issue-config.jpg?fit=max\&auto=format\&n=kiI3HgqRloEyGGgk\&q=85\&s=ac30848dd48bd66a4705e9eaf7533622) 3. Make changes to the configuration. * The integration option will be grayed out, but you can edit the other fields. 4. Click **Save issue config**. To delete an existing configuration: 1. Navigate to the Initiative and click the **Issue configs** tab. 2. On the right side of the issue config, click the 3 dots icon, then click **Delete config**. # Configuring OpEx Review Source: https://docs.cortex.io/improve/opex-review/configuring-opex Steps for configuring OpEx Review PUBLIC BETA You control what metrics the agent pulls and how often it generates an analysis. Add the metrics you want to track under each [DRIVE pillar](/solutions/drive-framework/the-drive-pillars) then drag to reorder them or edit and remove any metric from its row. Choose which parts of your organization the report covers and set a generation cadence. Save the configuration, and the agent starts generating reports on that schedule. > [!NOTE] > > As a Public Beta feature, OpEx Review is still evolving, and some options may change. Share feedback with your Customer Success Manager or through the in-product feedback controls. ## Configuring OpEx Review `Admins` and users with the `Configure OpEx` permission can configure OpEx Review. Before you run OpEx Review, decide which metrics it should include. Cortex pre-populates some metrics based on the integrations you've installed: deployment frequency, cycle time, incident frequency, and time to resolution. Follow the steps below to replace these metrics or select new ones. 1. From the main sidebar, select **OpEx Review**. 2. In the upper-right corner of the page, click **Edit**. 3. On the **Edit report** page, configure the following: 1. In the **Set report scope** section: 1. **Report type** - Select a report type from the dropdown. This controls how the report is organized and which teams get a separate report of their own. 1. **Team report** (default) - Metrics are broken down by team throughout the report. All teams in your workspace are included by default, so you can compare teams and drill into any of them from one place. You don't need to select teams individually to see per-team metrics. The report breaks down by team either way. Select **Specific teams** when you want one of the following: * To narrow the report to part of your organization, choose a single high-level team, e.g. Engineering. Its child teams are included automatically and roll up into it. * To give teams their own reports, choose up to 10. Each one gets a dedicated report with insights written about that team, alongside the aggregate report covering all of them. 2. **Domain report** - Works the same way, organized by domain instead of team. All domains are included by default. Select **Specific domains** when you want one of the following: * To narrow the report to part of your organization, choose a single high-level domain. Its child domains are included automatically and roll up into it. * To give domains their own reports, choose up to 10. Each one gets a dedicated report with insights written about that domain, alongside the aggregate report covering all of them. 2. In the **Choose metrics** section: 1. Metrics are grouped into six sections: Overview (Are there things we want to highlight?), then the five DRIVE pillars—Delivery, Reliability, Initiatives, Vigilance, and Efficiency. Overview sits above the pillars and holds what you want read first. Cortex starts you off with default metrics for the Delivery and Reliability pillars when the required integrations are installed. Adjust those defaults and add metrics to any section you want to track. 1. Click **Add metric**. The **Metric definition** side panel opens. 1. Select a metric from the dropdown. You can choose any out-of-the-box Eng Intelligence metric, custom metric, or Scorecard. If you have a Datadog integration, you can also add an SLO summary to the report alongside your metrics. 2. Click **View metric**. The metric is added to the pillar. 3. If you're running a team report, an extra option appears in the side panel. Select **Entity owner (Team)** or **Team (Author)** to define what "team" means for each metric. You can set this per metric, so a single report can use ownership for reliability and authorship for delivery. * Choose **Entity owner (Team)** when you're asking about the health of what a team owns. This is usually the right choice for reliability and quality metrics, where you want incidents and failures to land with the team responsible for the service, regardless of who touched it last. * Choose **Team (Author)** when you're asking about what a team is producing. This is usually the right choice for delivery metrics like deployment frequency and cycle time, where you want to see a team's own output rather than activity on their services by others. * **Example** * An engineer on the Platform team opens a pull request against a service owned by the Payments team. * With **Team (Author)**, the PR counts toward Platform. * With **Entity owner (Team)**, it counts toward Payments. 4. Optionally, select an **Operation** to set how the metric's data points are combined into a single value for the report period. Options include **Average**, **Sum**, **Max**, **Min**, **Median**, and **P95**. * For custom metrics, you can also select **Latest**. Instead of combining data points across the report period, **Latest** returns the most recent data point within it. If the period has no data points, the metric shows no value. * Use **Latest** for status-style custom metrics where only the current state matters, e.g. a metric that records `1` when a team's on-call rotation is set up and `0` when it isn't. Averaging that kind of metric across the period would blur the team's actual current state. * **Latest** isn't available for out-of-the-box Eng Intelligence metrics or Scorecards. 5. Optionally, add **filters** to narrow this metric's query. Because filters are per metric, you can add the same metric more than once and split each copy differently, e.g. Sev 0 incidents in one card and Sev 1 in another. 2. To reorder metrics within or between pillars, drag them by the **grip icon**. To edit or remove a metric, click the **pencil** or **trash icon** in its row. 3. Repeat as necessary. 3. In the **Set schedule** section: 1. Select how often the report should be generated. By default, reports are set to generate every two (2) weeks on Monday. 1. **Start date** - The date report generation begins. 2. **Report period** - How much data prior to each run date the report includes, in days or weeks. This also sets the cadence, so a two-week period generates a report every two (2) weeks. 3. **Repeat on** - The day of the week the report generates. 4. Do one of the following: 1. Click **Generate now** to run the report immediately. The configuration is saved automatically. A confirmation window opens showing the run date and the period the report covers. Click **Generate**. 2. Click **Save and close** to save the configuration without running a report. > [!NOTE] > > Manually generated reports can only be produced once a day. The limit resets at midnight UTC. Scheduled runs do not count against the limit. If a run is already in progress, **Generate now** is unavailable until it completes. ### What happens after you save The agent runs analyses on the schedule you set, beginning on your selected start date. You don't need to do anything between runs. Each report covers the window ending on its run date and extending back by the report period value. Because that same value sets the cadence, consecutive reports run back to back with no gaps or overlap. The report summary in the left pane of the **Edit report** page shows the exact dates the next report will cover. ![The 'Report summary' section.](https://mintcdn.com/cortex-290c0c42/IxDb4qc9F4yJyBqi/images/opex-report-overview.png?fit=max\&auto=format\&n=IxDb4qc9F4yJyBqi\&q=85\&s=c9714dfd1dc7d28916652a0f978c6d6d) Report dates are shown in UTC so they match the dates queried, and scheduled runs start at midnight UTC on the day you choose. While the agent generates the report, a status banner appears at the top of the OpEx Review page showing the period the upcoming report will cover. When generation finishes: * If you started the run with **Generate now**, the report opens automatically. * If it was a scheduled run, click **View latest report** in the banner. ### Changing the configuration later You can edit the configuration at any time. However, the change does not take effect the same way in every view: * The **summary** of an already-generated report doesn't change. It's a snapshot of what the configuration tracked when that report ran. Newly added metrics appear in the summary starting with the next generated report. * The **Metrics by** and any custom dashboard tabs rebuild from your current configuration, so past reports show your new metrics there too. Once Cortex generates your first report, see [Using the OpEx Review report](/improve/opex-review/using-opex) to read the executive briefing, break metrics down by team, and share the report. # OpEx Review FAQ Source: https://docs.cortex.io/improve/opex-review/opex-faq Frequently asked OpEx Review questions PUBLIC BETA These answers cover common questions about how OpEx Review works, what data it uses, and how that data is stored and secured. ## Getting started > **What do I need to get started?** > > To get started, Cortex recommends configuring at least 1-2 metrics in Delivery, 1-2 metrics in Reliability, and 1-2 Scorecards in Initiatives or Vigilance. This requires deployment, version control (for pull requests), and incident data flowing into Cortex from the following supported tools: > > | Pillar | Metric | Supported tools | Fallbacks | > | - | - | - | - | > | Delivery | Deployments | A CI/CD pipeline that calls the [Cortex deploys API](/api/rest/deploys) | Merged pull requests (version control), story points completed (Jira) | > | Delivery | Cycle time | GitHub or GitLab | Time to first review (Bitbucket and Azure DevOps), work item lead time (Jira) | > | Reliability | Incidents | PagerDuty or incident.io | Work items created, filtered by `type = incident` (Jira) | > | Reliability | Time to resolution | PagerDuty or incident.io | Change failure rate (from deployments), though it's a less reliable signal | > | Initiatives or Vigilance | 1-2 Scorecards | Scorecards configured in Cortex | None | > > For setup steps, see [Configuring OpEx Review](/improve/opex-review/configuring-opex). ## Data sources > **What data feeds the report?** > > The report uses all datasets available in [Eng Intelligence](/improve/eng-intelligence): > > * Version control > * Deployments > * Incidents > * Work items > * AI tooling > * Custom metrics > * Scorecard scores > > Additional Cortex data may become available to OpEx Review over time. > **How are production and non-production deployments distinguished?** > > Deployments can include optional environment information, which is used to separate production metrics from non-production metrics. To send environment information with your deployments, use the [Cortex deploys API](/api/rest/deploys). > **Does generating a report query my source systems or affect rate limits?** > > No. Cortex ingests and stores data from your integrations, and the report queries that stored data rather than your source systems. Generating a report adds no load or rate-limit pressure on your tools. > **Will reliability, observability, and security metrics be added?** > > Additional Cortex data may become available to OpEx Review over time. ## Data storage and security > **What data does Cortex store, and how is it secured?** > > Cortex stores the engineering metadata it ingests using the credentials you provide. That data is tenant-isolated and encrypted. Cortex maintains SOC 2 and ISO 27001 compliance. > **Does Cortex store my source code?** > > No. Cortex stores engineering metadata and event data, such as pull request, deployment, and work item metadata, Scorecard scores, and trace events. It doesn't store your source code or codebases. > **How long is data retained?** > > Cortex retains out-of-the-box Eng Intelligence metrics for at least 6 months and custom metrics for at least 24 months. If you need a longer retention period, contact your Customer Success Manager. ## How insights are generated > **How are highlights and concerns identified?** > > The agent works through a multi-step process across your engineering metadata and org structure: > > * It retrieves your data through structured calls, so every figure traces back to a real query result. > * It evaluates that data within the DRIVE framework (Delivery, Reliability, Initiatives, Vigilance, and Efficiency). > * It ties each signal to the teams, services, and domains responsible, using your catalog and ownership data, and rolls results up the way your organization is structured. > * It compares trends against historical baselines, so the report surfaces meaningful changes rather than normal week-to-week noise. > > The result is a prioritized, leadership-ready readout of what mattered most in the period, why it matters, and where to focus. > **How are AI-generated insights validated to prevent hallucinations?** > > Every metric in the report comes from Cortex's query engine through structured calls. Before each report is created, a grounding step checks each AI-generated insight against the underlying data. > **Which AI provider powers OpEx Review?** > > OpEx Review is powered by Anthropic's Claude, using different models for different tasks. ## Using Cortex AI in OpEx Review > **What can I ask Cortex AI in OpEx Review?** > > Cortex AI is built for follow-up questions on whatever metric or insight you're looking at, such as which teams are driving a change, how a metric compares to last quarter, or what a threshold means. Suggested prompts in the chat give you a place to start. > > For more examples, see [What you can ask](/improve/opex-review/using-opex-ai-chat#what-you-can-ask). > **What should I expect from a Cortex AI response?** > > Responses are short (typically two to four sentences or a brief bulleted list) and are meant to be discussed in your OpEx meeting. They call out specific teams or services, suggest a next step when there is one, and link to a relevant data source so you can dig in further. > > Cortex checks any metric it surfaces against the query engine, but as with any AI-generated summary, it's worth double-checking a number before it drives a decision. For more information, see [What to expect from a response](/improve/opex-review/using-opex-ai-chat#what-to-expect-from-a-response). ## Follow-ups > **How is the follow-up completion rate calculated?** > > The completion rate is the share of follow-ups from prior reports that have been completed. A follow-up added during a review starts counting in the next report, and open follow-ups keep carrying over until they're completed. For more, see ['Follow-ups' tab](/improve/opex-review/using-opex#follow-ups-tab). > **Does assigning a follow-up notify the assignee?** > > No. Assigning a follow-up doesn't yet send a notification and doesn't give the assignee access to OpEx Review. To see the follow-up, they need the `View OpEx` permission. For more, see [Tracking follow-ups](/improve/opex-review/using-opex#tracking-follow-ups). # Using the OpEx Review report Source: https://docs.cortex.io/improve/opex-review/using-opex PUBLIC BETA Each OpEx Review covers a single reporting period. The **Executive briefing** tab provides a recap narrating what changed across the five DRIVE pillars, and the **Metrics by** tab breaks those same metrics down by team or domain. The **Follow-ups** tab tracks the action items that come out of the review. Your own custom dashboards can be added as additional tabs. Because each report is tied to a fixed reporting period, you can share a link to the exact report you're viewing, or pull up a past period next to the current one. > [!NOTE] > > As a Public Beta feature, OpEx Review is still evolving, and some options may change. Share feedback with your Customer Success Manager or through the in-product feedback controls. ## Reading a report Users with the `View OpEx` permission can view a report. To access a report, select **OpEx Review** from the main sidebar. Under the page title, the header shows when the current report was generated, how often it generates, and when the next report is due. ![View of the OpEx Review page with header highlighted.](https://mintcdn.com/cortex-290c0c42/IxDb4qc9F4yJyBqi/images/opex-report-generic.png?fit=max\&auto=format\&n=IxDb4qc9F4yJyBqi\&q=85\&s=ddc8f08696c6e1a4ae38593171704ba4) ### Report tabs #### 'Executive briefing' tab The agent-generated executive briefing contains an overall summary and insights into each DRIVE metric. On the **Executive briefing** tab, you'll find an overview of the period's highlights and concerns, plus the option to ask Cortex AI anything about the report. ![The 'Executive briefing' tab in OpEx Review.](https://mintcdn.com/cortex-290c0c42/IxDb4qc9F4yJyBqi/images/opex-exec-briefing-tab.png?fit=max\&auto=format\&n=IxDb4qc9F4yJyBqi\&q=85\&s=62b8fc60826631d255234e83f20ddc56) The summary includes a short synopsis of the cycle: what improved, what regressed, and where to focus. #### 'Metrics by' tab The **Metrics by** tab presents your report's metrics as a table, with one row per team or domain depending on the report's scope, and a column for each metric the report tracks. Unlike the **Executive briefing** tab, the table isn't a snapshot. Cortex rebuilds it from your current report configuration each time you open it, so it always reflects what the review tracks rather than a stale export. ![The 'Metrics by' tab in OpEx Review.](https://mintcdn.com/cortex-290c0c42/IxDb4qc9F4yJyBqi/images/opex-metrics-by-tab.png?fit=max\&auto=format\&n=IxDb4qc9F4yJyBqi\&q=85\&s=71310c66515cd85919c1be048bc23e79) * Expand a team or domain to see its children and find where a number is actually coming from. * Click the card title to open the table as a standalone module. The report's dates carry over. ![The card title, highlighted, in OpEx Review.](https://mintcdn.com/cortex-290c0c42/IxDb4qc9F4yJyBqi/images/opex-card-title.png?fit=max\&auto=format\&n=IxDb4qc9F4yJyBqi\&q=85\&s=ab3f7897732da581729d80e06c332cbc) * Click the **Filter** icon in a card's upper-right corner to narrow that card by entity, entity type, group, domain, or entity owner. * Click any metric value to drill down to the trace view, showing the records behind that number. ![A metric value, highlighted, in OpEx Review.](https://mintcdn.com/cortex-290c0c42/IxDb4qc9F4yJyBqi/images/opex-card-value-number.png?fit=max\&auto=format\&n=IxDb4qc9F4yJyBqi\&q=85\&s=530bcc38116dc9518b605074535782ff) #### 'Follow-ups' tab The **Follow-ups** tab tracks the action items that come out of your reviews. It splits them into two lists: * **Added this report** - Follow-ups created since this report was generated. The date range next to the heading runs until the next report. * **Outstanding follow-ups** - Follow-ups carried into this review: every open follow-up, plus any completed since the previous report was generated. Above the **Outstanding follow-ups** list, cards show the number of open and completed follow-ups and the completion rate. The completion rate is the share of follow-ups from prior reports that have been completed. A new follow-up starts counting toward the completion rate in the next report. Click the **Open follow-ups due** or **Completed follow-ups** card to show only those follow-ups in the list. Each list shows the follow-up, its assignee, who created it and when, and the review cycle it's tracked against. To find a follow-up in either list: * Click **All statuses** to show all, open, or completed follow-ups. * Click the sort control to sort by assignee, creator, created date, or review cycle. The list is sorted by review cycle by default. * Click **Filter** to narrow the list by assignee, creator, or review cycle. * Use the search bar to find a follow-up by its text. To add and manage follow-ups, see [Tracking follow-ups](/improve/opex-review/using-opex#tracking-follow-ups). ### Selecting a reporting period The dropdown in the upper-left corner of the page lists each report by the dates it covers, with the most recent labeled **Latest**. Select a period to view that report. ![The 'Reporting period' dropdown in the upper-left corner of the page.](https://mintcdn.com/cortex-290c0c42/IxDb4qc9F4yJyBqi/images/opex-reporting-period-dropdown.png?fit=max\&auto=format\&n=IxDb4qc9F4yJyBqi\&q=85\&s=50072aafbd8d7c88d443d951ef839000) ### Selecting a team or domain If the report you're viewing is filtered to specific teams or domains, an additional dropdown appears next to the reporting period. Click the dropdown and select one of the following: * **Aggregate report** - All selected teams or domains rolled up together * **An individual team or domain** - That group's own narrated summary If your report covers your whole organization, there's only one report per period. To change which teams or domains a report covers, see [Configuring OpEx Review](/improve/opex-review/configuring-opex). ### Pillars and metrics On the **Executive briefing** tab, to the right of the summary, metrics are grouped into the **Overview** section and the five DRIVE pillars. Metrics can be KPIs (deployments, incidents, cycle time), Scorecards, or SLOs from Datadog. ![Pillars and metrics, highlighted, in OpEx Review.](https://mintcdn.com/cortex-290c0c42/IxDb4qc9F4yJyBqi/images/opex-pillars-metrics.png?fit=max\&auto=format\&n=IxDb4qc9F4yJyBqi\&q=85\&s=5060b4bc2ab3a0645b888a1cebfec7e9) For KPIs, each metric card shows: * The current value for the report period, with the change from the prior period beside it * A chart of the metric over the last 12 report periods, with completed periods in gray and the report's period in purple * A shaded band showing the range the metric normally sits in. * An AI insight interpreting the result For Scorecards, each metric card shows: * The distribution of levels of ladder-based scorecards, or the average score for point-based scorecards. * An AI insight interpreting the result For Datadog SLOs, each metric card shows: * How many SLOs are Passing, At risk, Failing, or have No data, as counts and a distribution bar * The change in each count since the previous period * Click a status, or the summary itself, to open the full SLO list. See Drilling into SLOs. KPIs and Scorecards also include an AI insight interpreting the result, along with a link to Ask Cortex AI so you can dig into what's behind a trend and ask follow-up questions. See [Digging deeper with Cortex AI](/improve/opex-review/using-opex#digging-deeper-with-cortex-ai) below. Insights name specific teams and numbers rather than restating the metric. In the example above, the deploy frequency insight identifies which three teams drove the volume and offers a read on whether the dip reflects scope changes or a pipeline problem. ### Drilling into a KPI On the **Executive briefing** tab, click a metric's value on any card to open a side panel scoped to the report's period and teams. ![A metric's value, highlighted, in OpEx Review.](https://mintcdn.com/cortex-290c0c42/IxDb4qc9F4yJyBqi/images/opex-card-value-drill.png?fit=max\&auto=format\&n=IxDb4qc9F4yJyBqi\&q=85\&s=d090045c3705a536f54ebb220d7021ea) In the side panel: * Select the **Explorer** tab to view a chart of the metric over time, with a breakdown table below it. * Select the **Trace view** tab to view a list of the underlying records behind the number. * At the top of the panel: * Click the date range to adjust it * Click **Filter** to narrow the scope * Click the **Group by** dropdown to slice the data differently * Click the **expand icon** to open the metric in Data Explorer ![The side panel, opened, when a metric value is drilled into.](https://mintcdn.com/cortex-290c0c42/IxDb4qc9F4yJyBqi/images/opex-side-panel-explorer.png?fit=max\&auto=format\&n=IxDb4qc9F4yJyBqi\&q=85\&s=ce330c570fc6e218e53ddd64a913716f) > [!NOTE] > > Scorecard-backed metrics don't yet support drill-down. ### Drilling into Datadog SLOs On the **Executive briefing** tab, click any number on the SLO summary to open a side panel listing every SLO the report measured. Clicking a status (Passing, At risk, Failing, or No data) opens the panel already filtered to it. The list opens sorted by least error budget remaining, so the SLOs closest to breaching are at the top. A blown budget goes negative and sorts above everything healthy. Each row shows the SLO's name, entity, target, status, and error budget left. Click a column header to re-sort. At the top of the panel: * Click Group by to group the table by Service or Group, or leave it on No grouping * Click Filter to narrow by Status or Service * Use Search SLOs to find an SLO by name * Click the SLO Name to open the SLO in Datadog > [!NOTE] > > The panel reads the SLO data captured when the report generated, so the numbers match the report rather than the vendor's current state. > [!NOTE] > > Scorecard-backed metrics don't yet support drill-down. ### Digging deeper with Cortex AI When a metric raises a question the report doesn't answer, ask Cortex AI without leaving the report. On the **Executive briefing** tab, ask Cortex AI directly from the summary area on the left or click **Ask Cortex AI** on a metric card. Enter your question in the Ask Cortex AI field, then press **Enter**. !['Ask Cortex AI', highlighted at the bottom of the summary and in a metric card.](https://mintcdn.com/cortex-290c0c42/IxDb4qc9F4yJyBqi/images/opex-ask-cortex-ai.png?fit=max\&auto=format\&n=IxDb4qc9F4yJyBqi\&q=85\&s=ebb7eb4da48fd2ca59e02e6f14a9c242) Cortex AI can query further breakdowns by team, entity, or time period, so it isn't limited to the insight you started from. For what you can ask and what to expect from a response, see [Using Cortex AI in OpEx Review](/improve/opex-review/using-opex-ai-chat). ### Sharing a report The **Share** button copies a link to the exact report you're viewing, including the reporting period, the team or domain selected, and the tab you're on. 1. Open the report, period, and team you want to share. 2. Click **Share** in the upper-right corner of the page. The link is copied to your clipboard. ![The share icon in OpEx Review.](https://mintcdn.com/cortex-290c0c42/IxDb4qc9F4yJyBqi/images/opex-share-button.png?fit=max\&auto=format\&n=IxDb4qc9F4yJyBqi\&q=85\&s=5b2bd807d9d9d030098175f9bdb2dfdb) Anyone you share the link with needs the `View OpEx` permission to access the report. ## Commenting on a report Comments let your team discuss a report right next to the numbers. You can comment on the summary, a highlight or concern, or any metric card, then reply in threads, mention teammates, and react with emoji. Each reporting period's report keeps its own comments. Users with the `View OpEx` permission can read comments. To add, reply to, or resolve comments, you also need the `Edit OpEx Comments` permission. Managers and admins have it by default. ### Adding a comment 1. On the **Executive briefing** tab, click the **comment icon** next to the summary, a highlight or concern, or in the upper-right corner of a metric card. If an item already has comments, the icon shows how many. 2. Enter your comment. To mention a teammate, team, entity, Scorecard, or Workflow, type `@` and select it from the list. You can also include links. 3. Click **Comment**. Each new comment starts its own thread, and an item can have several threads. Threads appear beside the item they belong to. ### Replying and reacting * To reply to a thread, click **Reply** below it. * To react to a comment, hover over it, click the **Add reaction** icon, then select an emoji. To add your own reaction to an existing one, click that reaction. * If a thread has a lot of replies, click **Show replies** to expand it. ### Managing a comment Hover over a comment, then click the **More actions** icon to see what you can do with it: * **Share** - Copies a link to the comment. * **Edit** - Updates your comment. Edited comments are labeled **(edited)**. * **Delete** - Removes your comment. You can only edit or delete comments you wrote. If you delete a comment by mistake, click **Undo** in the confirmation that appears. ### Resolving a thread When a discussion is settled, hover over the thread's first comment and click **Resolve**. Resolved threads move to the **Resolved** tab in the **Comments** panel. To reopen a thread you just resolved, click **Undo** in the confirmation that appears. ### Viewing all comments on a report Click **Comments** in the upper-right corner of the report to see the latest comments on the report, then click **Show all** to open the **Comments** side panel. In the side panel, you can: * Filter comments by author with the **All authors** dropdown. * Search comment text. * Switch between the **Open** and **Resolved** tabs. Unread comments are marked with a dot. ### Getting notified about comments Cortex can notify you when someone mentions you in a comment, and when there's activity on a thread you're part of. Both are on by default. Follow the steps below to choose which of these you get. 1. From the main sidebar, click your avatar in the bottom-left corner. 2. Select **Settings**. 3. From the **Settings** menu, locate the **Preferences** section, then select **My notifications**. 4. From the **Personal** tab, scroll to the OpEx section, then adjust the settings. For more information, see [Notifications](/configure/settings/notifications#adjusting-your-personal-notification-subscriptions). If you get a comment notification in Slack, you can reply to it in Slack. Your reply is posted to the thread as a comment. ## Tracking follow-ups Use follow-ups to capture the action items that come out of a review, assign an owner, and check on them at the next review. Users with the `View OpEx` permission can see follow-ups. Users with the `OpEx comments` permission can add, edit, complete, reopen, and delete them. **To add a follow-up**: 1. From any tab of the report, click **Add follow-up**. 2. Enter a description of the action item. 3. Optionally, assign it to anyone in Cortex and add a link, such as a ticket or doc. 4. Click **Save**. > [!NOTE] > > Assigning a follow-up doesn't notify the assignee or give them access to OpEx Review. To see the follow-up, they need the `View OpEx` permission. **To manage a follow-up**: On the **Follow-ups** tab, find the follow-up, then do any of the following: * **Edit** - Change the description, assignee, or link. * **Complete** - Mark the action item as done. * **Reopen** - Move a completed follow-up back to open. * **Delete** - Remove the follow-up from the review. Open follow-ups stay on the list from one review to the next, and each shows how many reviews it has carried over. ## Managing dashboard tabs Users with the `Configure OpEx` permission can change the report's tabs. You can add your own charts, KPI cards, and modules by pulling in any existing custom dashboard as a tab, so everything the meeting needs lives on one page. Dashboard tabs stay pinned to the report's period, but the data inside them is always current, not a snapshot. ![Custom tabs in OpEx Review.](https://mintcdn.com/cortex-290c0c42/IxDb4qc9F4yJyBqi/images/opex-additional-tabs.png?fit=max\&auto=format\&n=IxDb4qc9F4yJyBqi\&q=85\&s=5fb3f7c643a88f750d7fd0c03e15bd48) **To add a dashboard tab**: 1. Click the **gear icon** in the upper-right corner of the page. ![The gear icon in OpEx Review.](https://mintcdn.com/cortex-290c0c42/IxDb4qc9F4yJyBqi/images/opex-gear-icon.png?fit=max\&auto=format\&n=IxDb4qc9F4yJyBqi\&q=85\&s=e577762187408e0bcef33f33b34c94aa) 2. In the **Edit tabs** side panel, click **Add dashboard**. 3. Search for and select the dashboard you want to add. 4. Drag a tab by its grip icon to reorder. 5. Click **Apply to report**. **To manage a dashboard tab**: 1. Click the **gear icon** in the upper-right corner of the page. ![The gear icon in OpEx Review.](https://mintcdn.com/cortex-290c0c42/IxDb4qc9F4yJyBqi/images/opex-gear-icon.png?fit=max\&auto=format\&n=IxDb4qc9F4yJyBqi\&q=85\&s=e577762187408e0bcef33f33b34c94aa) 2. In the **Edit tabs** side panel, click the **overflow menu icon** next to the tab you want to manage. 3. Do any of the following: 1. **Edit dashboard** - Opens the dashboard in Eng Intelligence for editing. 2. **Rename dashboard** - Changes the dashboard and tab name. 3. **Share dashboard** - Copies a link to the dashboard. To share the whole report instead, click **Share** in the upper-right corner of the page. 4. **Duplicate dashboard** - Creates a copy and adds it as a new tab. 5. **Remove dashboard** - Removes the tab from the report. The dashboard itself isn't deleted. # Using Cortex AI in OpEx Review Source: https://docs.cortex.io/improve/opex-review/using-opex-ai-chat RESEARCH PREVIEW Cortex AI is Cortex's AI-powered chat assistant. It answers questions about your engineering data in plain language, using the same data that powers your Scorecards, dashboards, and reports. During an OpEx meeting, leaders often ask questions that no one in the room can answer on the spot, like which team is driving a spike or how a metric compares to last quarter. Normally, those questions become post-meeting follow-ups, and the discussion loses momentum. Cortex AI lets you ask the question and get an answer without leaving the report. > [!WARNING] > > **Cortex AI is not limited to the entities you can see** > > * Anyone with the Enable AI Chat permission can ask about any metric or scorecard score for any entity in your workspace, including ones hidden from them elsewhere in Cortex. > * Your own conversations stay private. > > ​Treat the `Enable AI Chat` permission as access to your organization's engineering data as a whole, and grant it accordingly. > [!NOTE] > > **Cortex AI chat is in Research Preview** > > * Responses can be slow, especially for questions spanning many teams or entities. > * Not all Cortex data is reachable from chat yet, so it can't answer every question about your organization. > * It can't take action on your behalf. It won't create or edit Scorecards, Initiatives, Dashboards, or Workflows, and it won't change the report's content or filters. > > We're actively working on improvements. Share feedback with your account team or through the in-product feedback controls. ## Accessing Cortex AI You can chat with Cortex AI from the summary section on the **Executive briefing** tab or from a metric card. `Admins` and users with the `Enable AI Chat` permission can access Cortex AI. **To access Cortex AI via the summary section**: 1. From the main sidebar, select **OpEx Review**. 2. From the **Executive briefing** tab, locate the summary section on the left side of the page. 3. At the bottom of the summary, do one of the following: 1. Select a pre-populated question. 2. Enter your question in the **Ask Cortex AI** field, then press **Enter**. ![Cortex AI options at the bottom of the summary, in OpEx Review.](https://mintcdn.com/cortex-290c0c42/IxDb4qc9F4yJyBqi/images/opex-cortex-ai-summary.png?fit=max\&auto=format\&n=IxDb4qc9F4yJyBqi\&q=85\&s=09b18dda8f872b933d5af621b693f174) **To access Cortex AI via a metric card**: 1. From the main sidebar, select **OpEx Review**. 2. From the **Executive briefing** tab, locate the metric card you want to dig into. 3. At the bottom of the card, click **Ask Cortex AI**. The side panel opens with the metric summary pre-populated. ![Opex Ask Cortex Ai (1)](https://mintcdn.com/cortex-290c0c42/IxDb4qc9F4yJyBqi/images/opex-ask-cortex-ai%20\(1\).png?fit=max\&auto=format\&n=IxDb4qc9F4yJyBqi\&q=85\&s=99715e2f46e8dcc7882b7d70a579bed4) 4. Do one of the following: 1. Select a pre-populated question. 2. Enter your question in the **Ask Cortex AI** field, then press **Enter**. Cortex AI has access to the same data behind the insight, plus the ability to query further breakdowns, such as by team, entity, or time period, so it isn't limited to just restating the insight you started from. Each chat is tied back to the metric it came from. If you open the panel again later, or view it as a full chat from the Cortex AI section in the main sidebar, you'll see a note showing which report and metric it was forked from, with a link back to that report. ## What you can ask Cortex AI is built for follow-up questions on whatever metric or insight you're looking at, for example: * ***Which teams or services are driving this increase?*** * ***How does this compare to last quarter?*** * ***What changed in the last two weeks?*** * Why a specific team's metric moved (for example, ***Why did Platform Engineering's deploy frequency drop?***) * How two teams or time periods compare * What a metric or threshold means, useful for less technical leaders in the room See the [Cortex AI prompt library](/get-started/cortex-ai-assistant/library) for a full list of prompt patterns organized by use case and role. ## Drafting follow-ups with Cortex AI When a discussion turns into an action item, ask Cortex AI to draft a [follow-up](/improve/opex-review/using-opex#tracking-follow-ups), for example ***Create a follow-up for Platform Engineering to look into the cycle time increase.*** Cortex AI drafts the follow-up as a card showing the action item, the assignee, and the review it will be tracked against. Review the draft, then click **Save follow-up**. Cortex AI doesn't create the follow-up until you save it. To draft follow-ups in chat, you need the `Edit OpEx Comments & Follow-ups` permission in addition to `Enable AI Chat`. ## What to expect from a response Answers are intended to be discussed in your OpEx meeting. Responses are typically two to four sentences, or a short bulleted list. Responses are designed to: * Call out specific teams or services by name where relevant * Suggest a next step when there is one * Link to a relevant data source, such as an entity page, filtered view, or Data Explorer, if it helps to dig in further Cortex checks any metric it surfaces against the query engine, but as with any AI-generated summary, it's worth double-checking a number before it drives a decision. ## Who can see your chats Your conversations are private to you. Nobody else in your organization can see them, including admins, and they aren't visible to anyone you send the URL to; a conversation link only opens for the person who created it. # Reports Source: https://docs.cortex.io/improve/reports Use reporting in Cortex to track entity performance against [Scorecards](/standardize/scorecards), analyze Scorecard performance over time, and more. Reports apply to published Scorecards in your workspace. Cortex offers several built-in reports: * [**Executive**](/improve/reports/executive-report) - A high-level view of owned and unowned entities, deploys, endpoints, and Scorecard performance. * [**All Scorecards**](/improve/reports/all-scorecards) - An aggregation of Scorecard reports, allowing you to quickly see which entities are meeting standards and which need more attention. * [**Birds eye**](/improve/reports/birds-eye) - A hierarchy-aware entity performance report that visualizes Scorecard data as a heat map. * [**Progress**](/improve/reports/progress-report) - A graph showing how performance of a Scorecard has changed over time. * [**Report card**](/improve/reports/report-card) - A high-level overview of any given Scorecard with the ability to visualize key performance indicators and top or bottom performers. Cortex also offers [CQL reports](/standardize/cql/cql-reports), allowing you to use Cortex Query Language (CQL) to query raw data in Cortex and build a custom report. > [!TIP] > > Want to learn more? Check out the Cortex Academy course on [Reports](https://academy.cortex.io/learn/course/cortex-reports). ## Reports overview video In the video below, learn how Scorecards, Initiatives, and Reports can be used together to drive business goals. [YouTube video player](https://www.youtube.com/embed/oIWbMlK7Qh4) ## Accessing reports From the main sidebar, expand **Reports** to see the list of available reports: ![The 'Reports' tab in the main sidebar.](https://mintcdn.com/cortex-290c0c42/TKBM5XkYAo_gc56V/images/reports-section.jpg?fit=max\&auto=format\&n=TKBM5XkYAo_gc56V\&q=85\&s=ba9335c523688a94c18908950922f649) ### Accessing reports from Scorecards You can also access reports directly from a Scorecard, under the **Reports** tab: ![Click the Reports tab in a Scorecard to access reports.](https://mintcdn.com/cortex-290c0c42/TKBM5XkYAo_gc56V/images/reports-in-scorecards.jpg?fit=max\&auto=format\&n=TKBM5XkYAo_gc56V\&q=85\&s=ef67ba087ffbdd33f9eb5f41a89b8fd8) ## Troubleshooting and FAQ See frequently asked questions below. **Why don't I see all of my expected Scorecards in a report?** Reports only apply to published Scorecards; they do not apply to draft Scorecards. If a Scorecard does not appear in your report, check if it's in draft form. # All Scorecards report Source: https://docs.cortex.io/improve/reports/all-scorecards The **All Scorecards report** gives you a consolidated view of performance across multiple Scorecards, so you can quickly see which areas are meeting standards and which need further attention. You can view entity relationships, teams, services, domains, and groups in a hierarchical view, and expand or collapse levels to understand org-wide trends and individual entity performance across multiple Scorecards simultaneously. > [!TIP] > > This report is especially helpful for platform or SRE teams who want to identify which services or domains are consistently out of compliance across different types of standards. ## Using the All Scorecards report Users with the `View Reports` permission can view and filter the All Scorecards report. The report is automatically generated when you navigate to the **All Scorecards** page in Cortex. **To access the All Scorecards report**: 1. From the main sidebar, expand **Reports**. 2. Select **All Scorecards**. The report displays entities, their average score across all Scorecards, and their individual scores per Scorecard. Click into a Scorecard to view more information.\ ![The All Scorecards report in Cortex.](https://mintcdn.com/cortex-290c0c42/pbVnLtaKpBTlBN5p/images/all-scorecards.jpeg?fit=max\&auto=format\&n=pbVnLtaKpBTlBN5p\&q=85\&s=c7d283dd5d691ba14b66e4f506e1a58e) > [!NOTE] > > **Switching between legacy and new views** > > Use the **Switch to legacy view** or **Switch to new view** link below the report header to toggle between experiences. ### Displaying Scorecards By default, the report displays all published Scorecards. Follow the steps below to customize which Scorecards appear in the list. Your selection is saved and will be remembered the next time you access the report. 1. From the main sidebar, expand **Reports**. 2. Select **All Scorecards**. 3. Click the **Scorecards filter**.\ ![The Scorecards filter at the top of the Scorecards list.](https://mintcdn.com/cortex-290c0c42/GZStB8YvzgOc1dXn/images/scorecards-filter.png?fit=max\&auto=format\&n=GZStB8YvzgOc1dXn\&q=85\&s=8f72fed048d95348a93c43580227843f) 4. Toggle off the Scorecards you don't want to appear in the list. 5. Optionally, if you don't want any Scorecards to appear, click **Show none**. 6. Click **Done**. 7. Optionally, click **Name** to reorder the list in descending alphabetical order. 8. Optionally, click **Display** to toggle off point calculations, e.g. "34/50". Point calculations are shown alongside score percentages in each Scorecard column. ### Grouping Scorecards By default, the report displays a flat view, though scores can be aggregated hierarchically by grouping on a dimension. Once grouped, expand and collapse levels to navigate the hierarchy. Any entities without the selected relationship defined appear under an ungrouped category. Available grouping options depend on your Scorecard and catalog configurations. For example, entity relationships appear as grouping options when their children are entities within at least one Scorecard. **To group Scorecards**: 1. From the main sidebar, expand **Reports**. 2. Select **All Scorecards**. 3. In the upper-left corner, click **Group by**.\ ![The 'Group by' option in the upper-left corner of the Scorecards list.](https://mintcdn.com/cortex-290c0c42/GZStB8YvzgOc1dXn/images/scorecards-group-by.png?fit=max\&auto=format\&n=GZStB8YvzgOc1dXn\&q=85\&s=8d4ce57e800a7a7acdc1c33226da64ad) 4. Select one of the following grouping options: 1. **Domain** - If selected, only domain entities appear in the list. 2. **Group** - If selected, Scorecards are listed alphabetically by group. 3. **Team** - If selected, only team entities appear in the list. 4. **Individual owner** - If selected, Scorecards are listed alphabetically by owner. 5. **Relationship** - If selected, Scorecards are listed alphabetically by relationship. ### Filtering the report To narrow down the content in your report, click **Filter** and select from the following options. Note that filter options depend on your Scorecard and catalog configurations. 1. From the main sidebar, expand **Reports**. 2. Select **All Scorecards**. 3. In the upper-right corner, click **Filter**.\ ![The 'Filter' option in the upper-right corner of the Scorecards list.](https://mintcdn.com/cortex-290c0c42/GZStB8YvzgOc1dXn/images/scorecards-filter-icon.png?fit=max\&auto=format\&n=GZStB8YvzgOc1dXn\&q=85\&s=49b2289b85e6dcd8deb0ac4c6d399f4f) 4. Filter by the following: * **Domain** – Filter by one or more domains. The **Include child domains** toggle is enabled by default, so filtering by a parent domain automatically includes its child domains. * **Entity** – Filter by specific entities. You can filter for entities within Scorecards or any direct parent of those entities. Filtering is not yet supported for grandparents or other entities higher up in the hierarchy. * **Entity Type** – Filter by entity type, i.e. services, resources, or custom entity types. * **Group** – Filter by custom groups. * **Individual: Owner** – Filter by entity owners. * **Level** – Filter by Scorecard level. * **Team** – Filter by one or more teams. The **Include child teams** toggle is enabled by default, so filtering by a parent team automatically includes its child teams. > [!NOTE] > > Domain and Team filters work for entities that belong to the selected domains or teams. If your Scorecard includes domain/team entities as their primary entity type, use the **Entity Type** filter to filter for a specific domain/team instead. ### **Understanding scores** Each Scorecard appears as a column showing score percentages. Entities earn points by passing rules, with each rule weighted based on significance. The score percentage reflects total points earned divided by total possible points. When viewing individual entity rows, each Scorecard column displays that entity's score percentage. When rows are aggregated (by team, domain, etc.), points are summed across all entities in that group to calculate the aggregate score percentage for each Scorecard. The total score across all selected Scorecards is calculated by summing points earned across all Scorecards and dividing by the total possible points across all Scorecards. ### Sharing the report You can share the All Scorecards report: * **Send a link** - Click **Share** from the report to copy the URL to your clipboard. You can share the link with anyone who has access to view the report in your Cortex workspace. * **Export as CSV** - In the upper right corner of the page, click **Export CSV** to download a CSV file of the report data. For large reports, click **Send email** to have the CSV delivered to your Cortex login email instead of waiting for the download. # Bird's eye report Source: https://docs.cortex.io/improve/reports/birds-eye > [!NOTE] > > Legacy Bird's eye report documentation can be found [here](/improve/reports/birds-eye/legacy-birds-eye-report). The [Bird’s eye report](https://app.getcortexapp.com/admin/reports/birdseye) provides deep insights into how entities are performing by visualizing Scorecard data as a heat map. This report is designed to give you a complete view of Scorecard performance across your organization and service hierarchies, helping you quickly identify and drill into hot spots. You can find the Bird's eye report in the main nav under **Reports > Bird's eye**. ## Using the Bird's eye report ![](https://mintlify.s3.us-west-1.amazonaws.com/cortex-290c0c42/images/Screenshot%202026-03-23%20at%2012.11.13%E2%80%AFPM.png) ### Applying a grouping By default, the report shows a flat view. To aggregate scores hierarchically, select **Group by** and choose your rollup dimension: Domain, Group, Level, Team, Individual: Owner, or Entity Relationships. Once grouped, navigate through the hierarchy by expanding and collapsing levels. Entities without the selected relationship defined appear under an ungrouped category. Available grouping options depend on the Scorecard's entities and your catalog configuration. For example, entity relationships appear as grouping options when their children are entities within the Scorecard. ### Drilling down Hover over an entity and click the more options menu to: * Go directly to the entity's details page * Preview the entity to get score statistics and the result of each rule evaluation * Focus and clear other entities from your view ### Applying a filter To narrow down the content in your report, filter your report by Domain, Entity, Entity Type, Group, Level, Team, or Individual: Owner. Available filter options depend on the Scorecard's entities and your catalog configuration. For\ example, Domain appears as a filter option when your Scorecard contains domains or entities assigned to domains. * **Domain –** Filter by one or more domains. The "Include child domains" toggle (on by default) ensures child domains are included when filtering by a parent domain. * **Entity** – Filter by specific entities. You can currently filter for entities within the Scorecard or any direct parent of those entities. Filtering is not yet supported for grandparents or other entities higher up in the hierarchy * **Entity Type** – Filter by entity type (e.g., services, resources, custom entity types) * **Failing Rules** – Filter by entities that are failing specific rules within the Scorecard * **Group** – Filter by custom groups * **Level** – Filter by Scorecard level (only available if the Scorecard is level-based) * **Individual: Owner** – Filter by entity owners * **Team** – Filter by one or more teams. The "Include child teams" toggle (on by default) ensures child teams are included when filtering by a parent team. > [!NOTE] > > Domain and Team filters work for entities that belong to the selected domains or teams. If your Scorecard includes domain/team entities as their primary entity type, use the Entity Type filter to filter for a specific domain/team instead. ### Understanding scores #### **Point-based Scorecards** Entities earn points by passing rules, with each rule weighted based on significance. The score percentage shown reflects total points earned divided by the total possible points. When rows are aggregated (by team, domain, etc.), points are summed across all entities in that group to calculate the aggregate score percentage. #### **Level-based Scorecards** Levels (such as Bronze, Silver, and Gold) are achieved by passing all rules within that level. Level-based Scorecards display the entity's current level along with its points and score percentage. Aggregated rows show a level distribution visualizing how many entities fall into each level, along with the summed points and score percentage. ### Switch between legacy and new views Use the *Switch to legacy view* or *Switch to new view* link below the report header to toggle between experiences. ## Sharing the Bird's eye report You can share the Bird's eye report: * **Send a link** - Click **Share** from the report to copy the URL to your clipboard. You can share the link with anyone who has access to view the report in your Cortex workspace. * **Export as CSV** - In the upper-right corner of the page, click **Export CSV** to download a CSV file of the report data. * Large reports can take a while to download. While the download is in progress, click **Email me** in the notification in the lower right corner of the page to have the CSV sent to your Cortex login email instead. # Executive report Source: https://docs.cortex.io/improve/reports/executive-report The [**Executive report**](https://app.getcortexapp.com/admin/reports/executive) offers a high-level view of everything happening in your organization — at a glance, you can see services, resources, deploys, [Scorecard](/standardize/scorecards) performance, domains, and teams. You can find the Executive report in the main nav under **Reports > Executive**. > [!TIP] > > Use this report to answer questions such as: How are we progressing as an organization? Where are our biggest risks? How do we prioritize platform or compliance work? ## Using the Executive report ### Generate an Executive report A report is automatically generated when you navigate to **Reports > Executive**. By default, the timeframe is set to the last month, but you can [choose a different timeframe](/improve/reports/executive-report#filter-the-report). ### Report overview The report’s Overview section provides key stats. Click into any of these tiles in the report to view more information: * The total number of entities * The number of teams and number of domains * The number of endpoints * This count helps you better understand the network of your dependencies. * The number of deploys ![](https://mintcdn.com/cortex-290c0c42/OnaYqLHqq-U_XM2R/images/exec-report-deploys.jpg?fit=max\&auto=format\&n=OnaYqLHqq-U_XM2R\&q=85\&s=00156543a70ed8a4770679efece5d4ee) * The number of groups * The number of unowned entities * These will display as red when at least one unowned entity exists in your catalog. ![](https://mintcdn.com/cortex-290c0c42/OnaYqLHqq-U_XM2R/images/executive-report.jpg?fit=max\&auto=format\&n=OnaYqLHqq-U_XM2R\&q=85\&s=10494fc5fefea831c1183f8592d9ee46) ### Filter the report While the Executive Report provides a view of your whole organization by default, you have the ability to filter by **Teams** or **Departments**. Click **Filter** in the upper right corner of the page. By default, the data is displayed for the last month. To change the timeframe, click **Last month** in the upper right corner and select a new range. ### Scorecards section #### Scorecards overview tab The Scorecards section gives you a snapshot of the average scores for your organization’s active Scorecards, and Scorecards progress shows you how scores have improved over time. ![](https://mintcdn.com/cortex-290c0c42/OnaYqLHqq-U_XM2R/images/exec-report-scorecards.jpg?fit=max\&auto=format\&n=OnaYqLHqq-U_XM2R\&q=85\&s=59c941516ee5507fe6a6dae164294214) The Leaderboard displays the average Scorecard score for each team; by default, this will display the aggregate of all Scorecards, but you can use the dropdown to view the Leaderboard by specific Scorecards. #### Scorecards Insights tab In the Insights tab, see the top-performing entities and the most at-risk entities per Scorecard: ![](https://mintcdn.com/cortex-290c0c42/OnaYqLHqq-U_XM2R/images/exec-report-insights.jpg?fit=max\&auto=format\&n=OnaYqLHqq-U_XM2R\&q=85\&s=a653fccf7810aeb67a42da7409b4af10) ### Deploys section Under Deploys, you can track the number of deploys over time. By default, this will evaluate All deploys, but you can unselect specific deploy groups, such as production, staging, and development. ![](https://mintcdn.com/cortex-290c0c42/OnaYqLHqq-U_XM2R/images/exec-deploys.jpg?fit=max\&auto=format\&n=OnaYqLHqq-U_XM2R\&q=85\&s=79e891590ded6efee4e02f4f642c6412) # Progress report Source: https://docs.cortex.io/improve/reports/progress-report The [Progress Report](https://app.getcortexapp.com/admin/reports/progress) shows you how performance on any given Scorecard has changed over time. You can find the Progress report in the main nav under **Reports > Progress**. > [!TIP] > > Use the Progress report to show how recent process changes or investments have paid off, or where progress has stalled. ## Using the Progress report ### Generate a Progress report Select a Scorecard from the list, then a report is automatically generated based on that Scorecard. ![](https://mintcdn.com/cortex-290c0c42/TKBM5XkYAo_gc56V/images/progress-report.jpg?fit=max\&auto=format\&n=TKBM5XkYAo_gc56V\&q=85\&s=c72716864c134c44ffc1462607e200a7) By default, the report displays data from the last month. To change the time range, click **Last month** in the upper right corner. ### Change the report grouping By default, the report displays average performance across all rules. You can also group by Team, owner, or group to see how different parts of your organization are performing over time. To change the group, click the **View by** dropdown in the upper left corner. ![](https://mintcdn.com/cortex-290c0c42/TKBM5XkYAo_gc56V/images/progress-report-grouping.jpg?fit=max\&auto=format\&n=TKBM5XkYAo_gc56V\&q=85\&s=75be20cddcac9b502a8257162b5a2b0a) When you group, the page displays the data as a line graph and as a table. The table displays the average score, median score, lowest score, and highest score for entities that belong to a team or domain. ![The progress report displays a graph and data in the table.](https://mintcdn.com/cortex-290c0c42/TKBM5XkYAo_gc56V/images/progress-team.jpg?fit=max\&auto=format\&n=TKBM5XkYAo_gc56V\&q=85\&s=c59d271917418ed7f8df9ac35657cef2) ### Filter the report In the upper left corner, click the **Rules** dropdown to select a specific rule and see its performance more granularly. ![](https://mintcdn.com/cortex-290c0c42/TKBM5XkYAo_gc56V/images/progress-rules-filter.jpg?fit=max\&auto=format\&n=TKBM5XkYAo_gc56V\&q=85\&s=2827a3e4eba0bf8bfb8ca49586829d74) In the upper right corner, click **Filter** to select a specific entity to filter the report by. ![](https://mintcdn.com/cortex-290c0c42/wjT-J8PNs9MwpcFs/images/progress-filter.jpg?fit=max\&auto=format\&n=wjT-J8PNs9MwpcFs\&q=85\&s=d1a8bba76d7ba6a0c698afa80bea67f8) ### Share the Progress report You can share the Progress report: * **Send a link**: Click **Share** in the upper right corner of the report to copy the URL to your clipboard. You can share the link with anyone who has access to view the report in your Cortex workspace. * The pre-configured link will display your report with the full breadcrumb trail. This not only gives others the same insights and understanding, but also provides an opportunity for team members to explore the data further on their own. * **Export as CSV**: In the upper right corner of the page, click **Export CSV** to download a CSV file of the report data. # Report card Source: https://docs.cortex.io/improve/reports/report-card The [Report Card](https://app.getcortexapp.com/admin/reports/reportcard) provides a high-level overview of any given [Scorecard](/standardize/scorecards), making it easy to visualize key performance indicators and the top and bottom performers. You can find the Report card in the main nav under **Reports > Report card**. > [!TIP] > > The Report card can be a helpful visual for engineering team retro meetings, as it summarizes wins and opportunities. ## Using the Report card ### Generate a Report card Select a Scorecard from the list, then a report is automatically generated based on that Scorecard. ### Report card metrics The Report card breaks performance down into several categories: * **Top entities** shows up to five entities with the highest scores in the selected Scorecard. This section shows each entity's name, tag, and score. * **Worst entities** shows up to five entities with the lowest scores in the selected Scorecard. This section shows the entity's name, tag, and score. ![](https://mintcdn.com/cortex-290c0c42/TKBM5XkYAo_gc56V/images/report-card-top.jpg?fit=max\&auto=format\&n=TKBM5XkYAo_gc56V\&q=85\&s=a41ec283018ffb1d105bb1ca21d72a70) * **Most improved** shows up to five entities that have improved the most in the selected Scorecard. This section shows each entity's name, tag, and score. You can also see how many places each entity has moved in rank among all entities. * **Worst drops** shows up to five entities that have dropped the most in score. This section shows each entity’s name, tag, and score. You can also see how many places the entity has moved in rank among all entities in the Scorecard. ![](https://mintcdn.com/cortex-290c0c42/TKBM5XkYAo_gc56V/images/report-card-middle.jpg?fit=max\&auto=format\&n=TKBM5XkYAo_gc56V\&q=85\&s=be07c77baf397d4c883782d9471c8dc7) * **Most moved** shows rules with the greatest percentage change in entities failing the specific rule. This section shows the rule definition and the percent change. In this case, a negative change is a good thing — it means fewer entities are failing that rule (in other words, more entities are passing the rule). * **Rules with highest risk** shows the rules with the lowest passing rates. This section shows the rule definition and the percent of entities failing a given rule. ![](https://mintcdn.com/cortex-290c0c42/TKBM5XkYAo_gc56V/images/report-card-bottom.jpg?fit=max\&auto=format\&n=TKBM5XkYAo_gc56V\&q=85\&s=b788e5e143d01d98f0d28a501b64d066) > [!TIP] > > Negative percentages in the **Most moved** section are a good thing - this means fewer entities are failing a given rule. # Home Source: https://docs.cortex.io/index Code is no longer the bottleneck. Everything else is. Code is no longer the bottleneck. Everything else is. Cortex is the EngOps Platform that keeps your entire engineering organization moving as one—fewer incidents, faster recovery, and developers spending time building instead of battling friction. Ask Cortex AI Welcome to Cortex Catalog your services, set engineering standards, and automate the work that connects them. ![Get started](https://mintcdn.com/cortex-290c0c42/vCS5fJP4w7e-qy0s/images/homepage-get-started.png?fit=max\&auto=format\&n=vCS5fJP4w7e-qy0s\&q=85\&s=10141647c9910c3dc3fa7a71075389bc) ## [Get started](https://docs.cortex.io/get-started/quickstart) Configure your workspace, connect your data, and learn how Cortex works Product Docs ![Build with the API](https://mintcdn.com/cortex-290c0c42/vCS5fJP4w7e-qy0s/images/homepage-api.png?fit=max\&auto=format\&n=vCS5fJP4w7e-qy0s\&q=85\&s=0f4a197e6114a12b1bb78de4a67e8b64) ## [Build with the API](https://docs.cortex.io/api) Use the REST API to automate work with entities, Scorecards, custom data, and more API Reference ![Best practices](https://mintcdn.com/cortex-290c0c42/vCS5fJP4w7e-qy0s/images/homepage-cookbooks.png?fit=max\&auto=format\&n=vCS5fJP4w7e-qy0s\&q=85\&s=7ffbf7b3f1413a013fea266b31ef56af) ## [Best practices](https://docs.cortex.io/guides) Follow proven, step-by-step recipes to tackle your engineering goals Cookbooks