# Cortex documentation

Code is no longer the bottleneck. Everything else is.

[Cortex](https://cortex.io/) 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.

### Welcome to Cortex

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-cover data-type="files"></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><span data-gb-custom-inline data-tag="emoji" data-code="1f4a1">💡</span> <strong>Solve Your Use Case</strong></td><td>Use Cortex to automate best practices and streamline actions for use cases like Production Readiness, AI Maturity, and Incident Management.</td><td></td><td><a href="/spaces/7F1UMLUuX7dkA693DijO">/spaces/7F1UMLUuX7dkA693DijO</a></td></tr><tr><td><span data-gb-custom-inline data-tag="emoji" data-code="26a1">⚡</span> <strong>Connect Data</strong></td><td>Pull in data from Git, Snyk, PagerDuty, and your other essential tools to build a complete picture of your software ecosystem.</td><td></td><td><a href="/pages/HKESDw5cb5tqBJcIAv3o">/pages/HKESDw5cb5tqBJcIAv3o</a></td></tr><tr><td>🔑 <strong>Define Ownership</strong></td><td>Establish clear ownership of services and entities to drive accountability, streamline incident response, and keep critical issues from falling through the cracks.</td><td></td><td><a href="/pages/3sA3UzKYpba4iDmzT7Gj">/pages/3sA3UzKYpba4iDmzT7Gj</a></td></tr><tr><td><span data-gb-custom-inline data-tag="emoji" data-code="1f5a5">🖥️</span> <strong>Configure GitOps</strong></td><td>Configure a GitOps workflow to manage entities in your Cortex workspace.</td><td></td><td><a href="/pages/KBttn6YUdEgixQGROHKf">/pages/KBttn6YUdEgixQGROHKf</a></td></tr><tr><td><span data-gb-custom-inline data-tag="emoji" data-code="1f517">🔗</span> <strong>Explore the API</strong></td><td>Build on top of Cortex using the API. Automate workflows, query your Catalog, and extend Scorecards.</td><td></td><td><a href="/spaces/nPgS8L9MAPtoOtdWdeDp">/spaces/nPgS8L9MAPtoOtdWdeDp</a></td></tr><tr><td><span data-gb-custom-inline data-tag="emoji" data-code="1f4c8">📈</span> <strong>Continuously Improve</strong></td><td>Measure baselines and identify bottlenecks. Take action and watch trends improve in real time.</td><td></td><td><a href="/pages/nZOyOBWYHpwwuH9q8HVF">/pages/nZOyOBWYHpwwuH9q8HVF</a></td></tr></tbody></table>

### Accelerate the path to engineering excellence

Engineering excellence is built on four pillars: **security**, **reliability**, **velocity**, and **efficiency**. But achieving all four requires more than good intentions. It requires clear ownership, complete visibility, and consistent standards across every team and service. Cortex gives you the foundation to get there.

Start with clear ownership and accountability so nothing falls through the cracks. Layer in complete visibility through the Catalog, drive a culture of continuous improvement with [Scorecards](/standardize/scorecards) and [Engineering Intelligence](/improve/eng-intelligence), and deliver a consistent developer experience through self-service [Workflows](/streamline/workflows).

***

#### SECURITY

Security best practices should be embedded in development from day one. Cortex lets you continuously check services for compliance and drive remediation with clear ownership and accountability.

* Monitor encryption, dependency health, and vulnerability status with customizable security compliance Scorecard templates.
* Automatically enforce security and compliance checks during service creation, ensuring every new service meets company-wide policies before it ships.
* Remediate vulnerabilities and compliance gaps by priority and deadline with [Initiatives](/improve/initiatives).
* Ensure consistent rollouts and CI/CD processes using Workflows.

<details>

<summary>How different personas drive security with Cortex</summary>

* **Engineering leaders** - Use [reports](/improve/reports) to understand current security posture and guide teams with actionable insights.
* **SREs** - Use Scorecards to maintain well-cataloged services, enabling faster and more confident incident response.
* **Security engineers** - Automate security checks, flag noncompliant services with Scorecards, and standardize remediation tasks with Workflows.

</details>

#### RELIABILITY

Reliability isn't just about uptime. It's about ensuring every service meets production-readiness standards before issues arise, and giving teams the context to respond quickly when they do.

* Automate readiness and operational maturity checks with customizable Scorecard templates that flag missing ownership, alerting, or logging configurations.
* Track DORA metrics and MTTR using Eng Intelligence dashboards.
* Enable fast incident response with Workflows to rollback, restart pods, and more.
* Give leaders and engineers a shared view of [Initiatives](/improve/initiatives), progress, and tasks on the [Engineering homepage](/streamline/homepage).

<details>

<summary>How different personas drive reliability with Cortex</summary>

* **Engineering leaders** - Use [reports](/improve/reports) to get a unified view of organization-wide service health and prioritize reliability Initiatives across teams.
* **Developers** - Use Scorecards to get clear visibility into whether services meet reliability standards.
* **SREs** - Automate production readiness checks via Scorecards to shift from reactive firefighting to proactive incident prevention.
* **Platform engineers** - Automate best practice enforcement via Scorecards and use Initiatives to keep reliability improvements moving by [syncing tasks directly with issue tracking tools](/improve/initiatives/issue-config).

</details>

#### VELOCITY

Slow, manual processes are one of the biggest blockers to shipping. Cortex removes the friction that keeps developers from moving fast without sacrificing standards.

* Provide automated golden paths that let developers bootstrap new services with security, observability, and operational standards pre-configured, so engineers aren't starting from scratch every time.
* Monitor cycle time, PR throughput, code coverage, and velocity trends with Eng Intelligence [velocity](/improve/eng-intelligence/dashboards/velocity-dashboard) and [DORA](/improve/eng-intelligence/dashboards/dora-dashboard) dashboards.
* Set clear standards and enforce best practices across teams and services with Scorecards.
* Automate common tasks like scaffolding new services or managing migrations with Workflows.
* Get quick answers about your workspace via [Cortex MCP](/get-started/cortex-ai-assistant/mcp) for faster decision-making.

<details>

<summary>How different personas drive velocity with Cortex</summary>

* **Engineering leaders** - Leverage productivity metrics from Eng Intelligence during performance reviews and coaching conversations.
* **Platform engineers** - Eliminate back-and-forth by setting up a Workflow to handle access requests as a single approval flow that integrates into existing tooling.
* **Developers** - Use the [Engineering homepage](/streamline/homepage) to stay focused on priorities, not operational overhead.

</details>

#### EFFICIENCY

Engineering efficiency means more than moving fast. It means eliminating waste, reducing redundant work, and ensuring every team is aligned to the same standards.

* Gain real-time visibility into your software ecosystem to identify orphaned services, stale dependencies, and underutilized infrastructure before they become costly problems.
* Use Scorecards to measure and enforce standards for consistency, resource utilization, and migrations.
* Use [Initiatives](/improve/initiatives) to keep teams aligned and ensure migrations are completed on time.
* Automate repeatable tasks with Workflows to free engineers from operational overhead.

<details>

<summary>How different personas drive efficiency with Cortex</summary>

* **Engineering leaders** - Manage cloud costs and improve resource utilization by identifying services that are no longer actively maintained or are running outdated dependencies.
* **Platform engineers** - Use Scorecards to enforce standards during migrations, keeping projects on track without manual review cycles.
* **Developers** - Use the [Engineering homepage](/streamline/homepage) to gain insight into their tasks and priorities at a glance.

</details>

### Cortex video overview

See Cortex in action.

{% embed url="<https://www.youtube.com/watch?v=0ugYI8r1DwI>" %}


# Cortex quick start guide

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.


# 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

{% hint style="info" %}
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.
{% endhint %}

Follow the steps below to log in to Cortex Cloud.&#x20;

1. Go to the Cortex login page:
   1. US environment - <https://app.getcortexapp.com/login>
   2. EU environment - <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:

{% embed url="<https://www.youtube.com/watch?v=yT6Ka0y_r80>" %}

{% hint style="info" %}
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.
{% endhint %}

### 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.

{% hint style="info" %}
The session timeout is a global configuration value and cannot currently be customized per tenant.
{% endhint %}

## 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.

{% hint style="info" %}
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.
{% endhint %}

### 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> 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.


# 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.


# 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/dashboards/dora-dashboard) - The speed, reliability, and efficiency of your development practices at a glance
  * [Velocity Dashboard](/improve/eng-intelligence/dashboards/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

<br>


# 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:&#x20;

* 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)&#x20;

Either way, responses are based on your actual Cortex data and honor each person's individual permissions.


# Additional Cortex resources

See [Further help](/resources/help) for additional resources.


# AI in Cortex

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. You can interact with Cortex wherever you work:

* **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.

However you ask, answers are grounded in your real Cortex data and respect each individual's permissions.&#x20;

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.


# Cortex AI prompt 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?*** | <p>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.</p><p>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.</p> |

#### Tracking AI adoption impact

| Prompt                                                                                              | What it does                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| --------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ***How has AI adoption impacted MTTR and deployment frequency over the last quarter?***             | <p>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.</p><p>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.</p>                                                              |
| ***Which teams have adopted AI tools, and how does their velocity compare to teams that haven't?*** | <p>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.</p><p>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.</p> |

#### 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?***                                              | <p>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.</p><p>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.</p> |
| ***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

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
* **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.

{% embed url="<https://www.youtube.com/watch?v=Tjm6nwO4ByQ>" %}


# Configuring the 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
docker pull ghcr.io/cortexapps/cortex-mcp:latest
```

#### Step 2: Configuring your MCP client

{% hint style="info" %}
Looking for IDE-specific setup? See the [README](https://github.com/cortexapps/cortex-mcp?tab=readme-ov-file#installation)
{% endhint %}

Update your MCP client's configuration file. Make sure to include your Cortex personal access token value for the `CORTEX_API_TOKEN` argument:

```json
{
  "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.

#### Step 1: Adding the remote MCP server to your MCP client

Follow the instructions below for Claude, VSCode, or Cursor. Make sure to replace `<CORTEX_TOKEN>` with the value of the personal access token you generated in Cortex.

**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 <CORTEX_TOKEN>"
```

**VSCode**

Add the following configuration to your `.vscode/mcp.json` file:

```json
{
  "servers": {
    "cortex": {
      "url": "https://mcp.cortex.io/mcp",
      "type": "http",
      "headers": {
        "Authorization": "Bearer <CORTEX_TOKEN>"
      }
    }
  }
}
```

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
{
  "mcpServers": {
    "cortex": {
      "type": "http",
      "url": "https://mcp.cortex.io/mcp",
      "headers": {
        "Authorization": "Bearer <CORTEX_TOKEN>"
      }
    }
  }
}
```

#### 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
{
  "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
{
  "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"
      ]
    }
  }
}
```


# Using the 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).

{% hint style="success" %}
**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).
{% endhint %}

## 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.

  <div align="left" data-with-frame="true"><figure><img src="/files/oSu5vTQw9dJmbNELDTID" alt="Screenshot 1 of MCP example conversation" width="375"><figcaption></figcaption></figure></div>
* 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.

  <div align="left" data-with-frame="true"><figure><img src="/files/rYLI7x9Xqbu7MUg4PS3N" alt="Screenshot 2 of MCP example conversation" width="375"><figcaption></figcaption></figure></div>
* You could ask about an entity's dependencies. The MCP client responds with a list of incoming and outgoing dependencies.

  <div align="left" data-with-frame="true"><figure><img src="/files/qAcNNxI5IzVOoA4Fgm2O" alt="Screenshot 3 of MCP example conversation" width="375"><figcaption></figcaption></figure></div>

## Available MCP tools

The Cortex MCP can use the following [Cortex REST API](https://docs.cortex.io/api/) endpoints:

<details>

<summary>Catalog / Entities</summary>

* [searchCatalog](/api/readme/catalog-entities#get-api-v1-catalog-search) - Find entities by relevance; the primary way to search the catalog
* [listAllEntities](/api/readme/catalog-entities#get-api-v1-catalog) - Enumerate entities by structured filters (groups, types, owners, repos)
* [getEntityDetails](/api/readme/catalog-entities#get-api-v1-catalog-tagorid) - Full details for one entity: metadata, ownership, hierarchy, relationships
* [getEntityDescriptor](/api/readme/catalog-entities#get-api-v1-catalog-tagorid-openapi) - A single entity's descriptor (optionally YAML)
* [listEntityDescriptors](/api/readme/catalog-entities#get-api-v1-catalog-descriptors) - List entity descriptors (optionally YAML)

**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."

</details>

<details>

<summary>Custom data and events</summary>

* [getCustomDataForEntity](/api/readme/custom-data#get-api-v1-catalog-tagorid-custom-data) - All custom key-value data for an entity
* [getCustomDataForEntityByKey](/api/readme/custom-data#get-api-v1-catalog-tagorid-custom-data-key) - One custom data value by key
* [listCustomEventsForEntity](/api/readme/custom-events#get-api-v1-catalog-tagorid-custom-events) - Custom events for an entity (filter by type/time)
* [getCustomEventForEntityByUuid](/api/readme/custom-events#get-api-v1-catalog-tagorid-custom-events-uuid) - One custom event by UUID

</details>

<details>

<summary>Dependencies and relationships</summary>

* [listDependenciesForEntity](/api/readme/dependencies#get-api-v1-catalog-callertag-dependencies) - Incoming + outgoing dependencies (blast radius)
* [getDependency](/api/readme/dependencies#get-api-v1-catalog-callertag-dependencies-calleetag) - Details of one dependency between two entities
* [listRelationshipTypes](/api/readme/entity-relationship-types#get-api-v1-relationship-types) - All relationship types
* [getRelationshipTypeDetails](/api/readme/entity-relationship-types#get-api-v1-relationship-types-relationshiptypetag) - Config/rules for one relationship type
* [listEntityRelationships](/api/readme/entity-relationships#get-api-v1-relationships-relationshiptypetag) - Full org graph for a relationship type
* [listEntitySourcesForRelationshipType](/api/readme/entity-relationships#get-api-v1-catalog-tagorid-relationships-relationshiptypetag-sources) - Sources for a relationship type & entity
* [listEntityDestinationsForRelationshipType](/api/readme/entity-relationships#get-api-v1-catalog-tagorid-relationships-relationshiptypetag-destinations) - Destinations for a relationship type & entity

</details>

<details>

<summary>Scorecards</summary>

* [listScorecards](/api/readme/scorecards#get-api-v1-scorecards) - All scorecards (filter by group/entity/team)
* [getScorecard](/api/readme/scorecards#get-api-v1-scorecards-tag) - Full scorecard config, rules, levels, weights
* [listScorecardScores](/api/readme/scorecards#get-api-v1-scorecards-tag-scores) - Scores for all entities on a scorecard
* [getScorecardNextStepsForEntity](/api/readme/scorecards#get-api-v1-scorecards-tag-next-steps) - Steps to reach an entity's next maturity level

</details>

<details>

<summary>Initiatives</summary>

* [listInitiatives](/api/readme/initiatives#get-api-v1-initiatives) - All initiatives (optional draft/expired)
* [getInitiative](/api/readme/initiatives#get-api-v1-initiatives-cid) - One initiative's goals, timeline, targets, progress

</details>

<details>

<summary>Metrics</summary>

* [getCustomMetricData](/api/readme/custom-metrics#get-api-v1-eng-intel-custom-metrics-custommetrickey-entity-tagorid) - Custom metric time-series for an entity

**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."

</details>

<details>

<summary>Teams, on-call, and deploys</summary>

* [getTeamDetails](/api/readme/teams#get-api-v1-teams-tagorid) - Team members, Slack channels, metadata
* [getCurrentOncallForEntity](/api/readme/on-call#get-api-v1-catalog-tagorid-integrations-oncall-current) - Real-time on-call for an entity
* [getDeploysForEntity](/api/readme/deploys#get-api-v1-catalog-tagorid-deploys) - Deployment history for an entity

</details>

<details>

<summary>Docs and meta</summary>

* `query_docs` - This tool queries the Cortex help center.
* `get_more_tools` - This tool discovers additional specialized tools.

</details>

### 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.

**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?*

## 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?**

No, you cannot make changes or write data via the Cortex MCP. The MCP is strictly read-only—it only handles `GET` requests and cannot modify or write data.

**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.


# Ingesting data into Cortex

Bringing your data into Cortex unlocks everything else the platform can do. It's the foundation for data-driven decisions, clearer accountability, and a shared understanding of how your engineering organization actually works.\
\
Once your services, repositories, teams, and infrastructure are connected, Cortex stitches it all into a complete, always-current view of your ecosystem. That view is what makes it possible to track ownership, enforce production readiness through Scorecards, standardize common developer Workflows, and give every engineer the context they need to find what they're looking for, see how the pieces fit together, and make better decisions at every stage of the development lifecycle.

## How Cortex handles data modeling

Cortex is built to mirror how your organization actually works. You get the flexibility to model your business logic across your data, and the structure to make sure that logic stays consistent everywhere it appears so your workspace reflects reality instead of forcing your team to work around it.

Cortex solves for this by giving you the flexibility to mirror your unique business logic across your data, and the structure to persist that logic everywhere:

* **Foundational, configurable data models**. A strong starting point you can shape to fit your environment.
* **Available, extensible integrations**. Connect the tools you already use, and extend them as your needs grow.
* **Complete, customizable experience**. A polished workspace out of the box, ready to be tailored to your team.

**The result**: a consistent developer workflow and an experience built around how your organization actually operates, making it easier to represent your services and infrastructure accurately in Cortex.

See an [overview of Cortex data concepts below](#cortex-data-concepts-reference-table).

{% hint style="success" %}
**Need assistance with data modeling?**\
To ensure a smooth implementation, most of our customers partner with Cortex Professional Services (PS) for hands-on assistance, including expert guidance on data modeling. Contact <help@cortex.io> to learn more.
{% endhint %}

## Connecting your data

Connecting your data in Cortex comes down to three building blocks: **entities**, **catalogs**, and **integrations**. Together, they determine what lives in your workspace and how it stays accurate over time.\
\
[Entities](/ingesting-data-into-cortex/entities-overview/entities) are the foundation. An entity is an object that represents a software construct such as a service, a piece of infrastructure, a team, or anything else worth tracking. Entities are defined in YAML, can pull in data from your integrations, can have dependencies, can be organized into hierarchies, and can connect to other entities through entity relationships. You can also enforce standards across them using Scorecards.\
\
[Catalogs](/ingesting-data-into-cortex/catalogs) are how you organize entities into meaningful groups. A catalog is a defined selection of entities used to track and store information about the components that make up your infrastructure.\
\
[Integrations](/ingesting-data-into-cortex/integrations) are how the data flows in. Cortex supports a broad set of integrations that pull live data from the tools your team already uses, creating a single pane of glass across your engineering ecosystem.

{% hint style="success" %}
Want to learn more? Check out the Cortex Academy course on [Catalogs, Entities, and Relationships](https://academy.cortex.io/courses/understanding-understanding-catalogs-entities-and-relationships).
{% endhint %}

## Cortex data concepts reference table

Learn about the basic data concepts for Cortex below.

<table><thead><tr><th width="158.5728759765625">Concept</th><th width="548.3333129882812">Definition</th></tr></thead><tbody><tr><td><strong>Team</strong></td><td>A group of humans responsible for something</td></tr><tr><td><strong>Service</strong></td><td>A running technical component (API, job, infra service)</td></tr><tr><td><strong>Domain</strong></td><td>A foundational grouping layer that represents a logical or functional area of your organization. Domains form the base hierarchy that organizes entities under stable, high-level boundaries. Each domain reflects a cohesive area of ownership, business function, or technical responsibility.</td></tr><tr><td><strong>Custom entity</strong></td><td>Any other trackable thing - ML models, Clients, environment, release, Products. Use this when "service" doesn't fit.</td></tr><tr><td><strong>Catalog</strong></td><td>A folder-like visual container, for UI organization only</td></tr><tr><td><strong>Group</strong></td><td>A logical collection for search, filtering, and reporting—similar to a label or tag</td></tr><tr><td><strong>Dependency</strong></td><td>One entity relies on another; enables impact analysis and notifications</td></tr><tr><td><strong>Ownership</strong></td><td>The accountability link between a team and entity</td></tr><tr><td><strong>Entity relationship</strong></td><td>The generic link between entities</td></tr><tr><td><strong>Hierarchy</strong></td><td>Parent-child or part-of structure; enables inheritance ownership</td></tr></tbody></table>


# Entities overview

Entities are the foundational building blocks for representing your software ecosystem. Each entity models a distinct software construct—like a service, library, or team—giving your organization a shared, structured way to describe what exists and how it fits together. A defined collection of entities forms a [catalog](/ingesting-data-into-cortex/catalogs): a single source of truth that everyone, from engineers to leadership, can rely on.

Entities are designed to be both flexible and interconnected. They're defined in YAML so they're portable and version-controlled, enriched through integrations that pull in live data from the tools you already use, and measured against standards through Scorecards to drive quality and consistency over time.

Every entity has a dedicated page that brings its data together in one place, making it easy to understand context, ownership, and health at a glance. See [Entity details](/ingesting-data-into-cortex/entities-overview/entities/details) for more information.

{% hint style="success" %}
Want to learn more? Check out the Cortex Academy course on [Catalogs, Entities, and Relationships](https://academy.cortex.io/courses/understanding-understanding-catalogs-entities-and-relationships).
{% endhint %}

## Catalog and entities overview video

The video below shows how Cortex catalogs your engineering assets to improve visibility, adoption, and productivity:

{% embed url="<https://www.youtube.com/watch?v=A5w6ebxGbeg>" %}

## Entity types

Choose from the default entity types or [define your own](#custom-entity-types).

### **Default entity types**

Cortex provides a set of built-in entity types that cover the most common building blocks of a software organization. These defaults give you a strong foundation out of the box, so you can start cataloging your ecosystem without needing to design a schema from scratch.

<table><thead><tr><th width="158.5">Entity type</th><th>Purpose</th><th>Typical use</th></tr></thead><tbody><tr><td><strong>Services</strong></td><td>Represent codebase-like modules</td><td>Microservices, libraries, components</td></tr><tr><td><strong>Domains</strong></td><td>Group entities into logical units</td><td>Product areas, business capabilities, system boundaries</td></tr><tr><td><strong>Teams</strong></td><td>Represent the 'people side' of your catalog</td><td>Ownership, membership, contact info</td></tr><tr><td><strong>Cloud resources</strong></td><td>Sync infrastructure into your catalog</td><td>AWS, Azure, and Google Cloud resources</td></tr></tbody></table>

**Services** are the core of your catalog and the default entity type. Use them to represent any codebase-like module, e.g. microservices, libraries, components, and similar building blocks. Services are typically where the majority of your catalog activity happens, since they connect to code, deployments, ownership, and quality standards. See [Adding services](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/add-services).

**Domains** let you group services, resources, and other domains into hierarchical, logical units. They're useful for modeling how your organization actually thinks about its software—by product area, business capability, or system boundary—and for rolling up insights across related entities. See [Adding domains](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/domains).

**Teams** represent the people side of your catalog. Use them to capture team membership, ownership relationships, and contact information, so it's always clear who's responsible for what. See [Adding teams](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/teams).

**Cloud resources** can be pulled in directly from your cloud providers and represented as their corresponding entity types, keeping your catalog in sync with what's actually running in your infrastructure:

* For **AWS**, choose which resource types to include in your [AWS integration settings](https://app.getcortexapp.com/admin/settings/aws?activeTab=settings).
* For **Azure**, choose which resource types to include in your [Azure Resources integration settings](https://app.getcortexapp.com/admin/settings/azureresources).
* For **Google Cloud**, see the list of [supported entity types](/ingesting-data-into-cortex/integrations/google#supported-google-entity-types).

### **Custom entity types**

While Cortex's built-in entity types cover most common needs, every organization has its own way of modeling its software ecosystem. Custom entity types let you extend your catalog to reflect the concepts that matter to your teams, whether that's APIs, data pipelines, ML models, or anything else you want to track.

You can create unlimited custom entity types through the Cortex UI or API. Once a type is defined, you can begin adding entities of that type using the UI, API, or GitOps, just like you would with built-in types.

See [Adding custom entity types](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/entity-types) for more information.


# Managing entities

This article provides an overview of how to manage entities in Cortex. For an overview of how entities work, see [Entities overview](/ingesting-data-into-cortex/entities-overview).

## Adjusting general settings for entities

Admins and users with the `Configure Settings` permission can adjust system-wide settings for entities under **Settings > Entities > General.** See [Entity settings](/configure/settings/entity-settings).

## Defining entities with YAML

Every entity in your Cortex catalog is defined by a YAML file known as the Cortex entity descriptor (or *Cortex YAML*, named after the `cortex.yaml` file used in the [GitOps approach](#managing-entities-via-gitops)). This applies whether you manage entities through the UI or GitOps—the descriptor is the underlying source of truth either way.

You can extend an entity by adding metadata to the `info` section of its descriptor. Throughout the docs, you'll see snippets prefixed with `x-cortex-*`; these are descriptor blocks that belong inside `info` and unlock additional Cortex functionality.

See [Defining entities with YAML](/ingesting-data-into-cortex/entities-overview/entities/yaml) for more information.

## Unique identifiers for entities

### **Cortex tag**

The Cortex tag (formerly the *entity tag*) is a customizable, unique identifier used to reference an entity throughout Cortex. It's defined by the `x-cortex-tag` value in an entity's YAML file and powers core functionality like declaring dependencies between entities or looking up information through the [Cortex AI Assistant](/get-started/cortex-ai-assistant).

Each Cortex tag must be globally unique across all entities in your workspace.

**Changing a Cortex tag**

Editing an entity's `x-cortex-tag` doesn't rename the existing entity, it creates a new one. Cortex generates a new entity with the updated tag and leaves the original entity untouched, regardless of whether the change is made through the UI editor, the API, or GitOps. Both entities continue to exist in your catalog until you archive or delete the original.

**Reusing a Cortex tag**

A Cortex tag can only be associated with one entity at a time. To reuse a tag that's already in use, the entity currently holding it must be [archived](/ingesting-data-into-cortex/entities-overview/entities/archiving-entities) first.

**Using forward slashes in a Cortex tag**

Cortex tags may contain forward slashes (`/`), including leading, trailing, and consecutive slashes, e.g.  `payments/checkout` or `/services/payments-api`).

When you reference a tag that contains forward slashes in an API request path, URL-encode each slash as `%2F`. Cortex matches the tag exactly as encoded—including any leading, trailing, or consecutive slashes—and does not collapse repeated slashes.

For example, to archive an entity whose tag is `/services/payments-api`:

```
PUT https://api.getcortexapp.com/api/v1/catalog/%2Fservices%2Fpayments-api/archive
```

{% hint style="info" %}
Tags containing slashes (including consecutive slashes such as `//`) are supported through the API only. The Cortex UI does not support creating or editing tags with leading, trailing, or consecutive slashes, so behavior between the API and UI differs by design.
{% endhint %}

### **Cortex ID**

The Cortex ID (CID) is a unique, immutable identifier assigned to every entity in Cortex. Unlike the Cortex tag, which you define and can change, the CID is automatically generated, fixed for the life of the entity, and 18 characters long, making it ideal for historical tracking, reporting, and any system of record outside of Cortex.

You can use the CID anywhere you'd reference an entity: in the API, in CQL queries, throughout the app, and with the Cortex AI Assistant.

**Where to find the CID**

The CID appears in an entity's URL and at the top of its entity page. It doesn't appear in the entity's YAML file, since it can't be modified.

<div align="left" data-with-frame="true"><figure><img src="/files/Ah50yX6uLLpk12UU5mPu" alt="The CID in the URL and on the entity&#x27;s details page." width="563"><figcaption></figcaption></figure></div>

## Managing entities via GitOps

Accounts are configured to edit entities through the UI by default. It's strongly recommended to start with the UI editor, which includes a built-in YAML editor, then moving to GitOps when you're ready to scale.

Follow the steps below to enforce GitOps-only creation and editing of entities.

1. From the main sidebar, click your avatar in the bottom-left corner.
2. Click **Settings**.
3. From the **Settings** menu, locate the **Workspace** section, then click **GitOps**.
4. From the **Entities** tab, scroll to **Options by entity type**.
5. Do the following:
   1. To only allow editing of entities via GitOps, toggle off **Enable UI editing for new entity types**.
   2. To only allow creation of entities via GitOps, toggle off **Enable UI importing for new entities**.
   3. To override these settings for a specific entity type, disable the **UI editing** and **UI importing** toggles next to that type in the list. This enforces a GitOps-only approach for that entity type.<br>

      <div align="left" data-with-frame="true"><figure><img src="/files/DPqabYfNPJZDXHKJTlNk" alt="Entity types list with UI editing and UI importing toggles disabled for a selected type." width="375"><figcaption></figcaption></figure></div>

#### Things to keep in mind when using GitOps

When using GitOps, you can define any number of entities in any repository.

* Domain definitions should live in the `.cortex/domains` directory in your repository.
* Team definitions should live in the `.cortex/teams` directory in your repository.

Entity definitions can live in one central repository, or alongside the service they describe in that service's own repository.

See the single repository example below:

```
.
└── .cortex
    ├── catalog
    │   ├── database.yml
    │   ├── s3-bucket.yml
    │   ├── auth-service.yml
    │   └── billing-service.yml
    ├── domains
    │   ├── billing-domain.yml
    │   └── health-domain.yml
    ├── teams
    │   ├── eng-team.yml
    │   └── sre-team.yml
```

See [Using GitOps for Cortex](/configure/gitops) for more information.

## Adding entities to catalogs

Each catalog has entity type criteria that determine which entities it includes. When an entity is created or imported, it's automatically added to any catalog whose criteria it meets. You set these criteria when [creating a custom catalog](/ingesting-data-into-cortex/catalogs#custom-catalogs).

Default catalogs have their entity type criteria set automatically:

* The **Services** catalog contains `service` entity types
* The **Domains** catalog contains `domain` entity types
* The **Teams** catalog contains `team` entity types
* The **Infrastructure** catalog contains any entities that are *not* the types `service`, `domain`, or `team`.
  * Its catalog filter is set to exclude the types `service`, `domain`, and `team`:<br>

    <div align="left" data-with-frame="true"><figure><img src="/files/Gt5XhNkFATrVeCgR7BeU" alt="Image of an entity&#x27;s catalog filter." width="301"><figcaption></figcaption></figure></div>
  * By default, any [custom entity types](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/entity-types) you create belong to the Infrastructure catalog. If you don't want an entity type to belong to this catalog, you can add the entity type to a different catalog.

To learn more about adding each type of entity to Cortex, see:

* [Adding services](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/add-services)
* [Adding domains](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/domains)
* [Adding teams](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/teams)
* [Adding custom entity types](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/entity-types)

### Managing entities across catalogs

The **All entities** page lists every entity that's been imported into Cortex, regardless of type. To open it, expand **Catalogs** in the main sidebar and select **All entities**. The page opens to the **Mine** tab if you own any entities, and defaults to the **All entities** tab otherwise.

Each row shows the entity's name and tag. Most workspaces start with just a few dozen entities, but catalogs often grow to hundreds (or thousands!) of entities over time as more of your ecosystem is brought into Cortex.

#### Searching across and filtering entities

<div align="left" data-with-frame="true"><figure><img src="/files/yzzZwYpmndcKzmOTWaan" alt="The search and filter options in the upper-right corner of the page." width="563"><figcaption></figcaption></figure></div>

There are several ways to search and filter your entities list.

1. From the main sidebar, expand **Catalogs**, then select **All entities.**
2. Do one of the following:
   * Select the **All** tab to search and filter across all of your organization's entities.
   * Select the **Mine** tab to search and filter only the entities you own.
   * Note that Cortex saves your selection and restores it the next time you open this page.
3. Do any or all of the following:
   * To find specific entities, use the search bar in the upper-right corner of the entities list and type to search.
   * Click **Name** to select whether you want to sort by name or identifier, and whether to sort by ascending or descending order.
   * Click **Display** to choose whether to show archived entities in the list, and select which columns to display alongside entities.
     * **Incidents** - Displays how many active incidents are associated with a given entity. This information is pulled from FireHydrant, incident.io, PagerDuty, and Rootly.
     * **Health** - When you click into this column in an entity's row, you can view more information about:
       * **Monitors** - Shows how entities are performing against monitors you’ve created in your APM. When an entity is passing all monitors, this cell will display `All OK`; otherwise, it displays `Failing`, `Warning`, or `No Data`, along with how many monitors the entity is not hitting. This information is pulled from Datadog.
       * **Error rate** - Shows the percentage of transactions that result in a failure during a pre-specified window. This information is pulled from New Relic.
       * **Apdex (Application Performance Index)** - Ratio of the number of satisfied and tolerating requests to the total number requests made. This information is pulled from New Relic.<br>

         <div align="left" data-with-frame="true"><figure><img src="/files/9uAkJtwfj7iG0vPclWjs" alt="Shows the health and incidents columns on the entities page." width="304"><figcaption></figcaption></figure></div>
     * Columns that rely on an integration display **Not connected** when the integration hasn't been set up. If the integration is connected but the entity has no associated data or configuration, the cell displays **None** instead.
   * Click **Filter** to narrow down your list by associated Git repository, unowned entities, AWS account ID or region, domain, entity type, group, team, or user.

#### Viewing entity types

Select the **Entity types** tab to view all entity types in your workspace. Click any entity type to see more details about it.

<div align="left" data-with-frame="true"><figure><img src="/files/S983moTAqbQUZqwfL6Zr" alt="The &#x27;Entity types&#x27; tab shows all entity types in your organization." width="563"><figcaption></figcaption></figure></div>

Built-in entity types are marked with a Cortex logo. Hover over the logo to see a "Powered by Cortex" banner. Any other types in the list are custom entity types created for your workspace. To learn more about creating your own, see [Adding custom entity types](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/entity-types).

<div align="left" data-with-frame="true"><figure><img src="/files/B6MeZaglbUSl9Rde7d96" alt="The &#x27;Powered by Cortex&#x27; icon appears next to a built-in entity in the Entities list." width="278"><figcaption></figcaption></figure></div>

#### Changing an entity's type

Entities can be reclassified to a different type as their role in your catalog evolves. For example, an entity originally created as a service could later be changed to a domain. This gives you flexibility to restructure your catalog as your organization changes—useful when entities were initially imported under the wrong type, or when you want to consolidate, split, or rethink how parts of your ecosystem are modeled.

Admins or users with the `Configure Settings` permission can change an entity's type.

**Prerequisites**

1. Toggle on the option to change an entity type:
   1. From the main sidebar, click your avatar in the bottom-left corner.
   2. Click **Settings**.
   3. From the **Settings** menu, locate the **Workspace** section, then click **Entities**.
   4. Click **General**.
   5. In the **Entity settings** section, toggle on **Enable changing entity type**.

{% hint style="info" %}
If you'd rather keep entity types fixed after creation, keep this option toggled off to enforce stability across your catalog.
{% endhint %}

**To change an entity's type**:

{% hint style="warning" %}
Changing an entity's type could result in broken dependencies and hierarchies.
{% endhint %}

Update the entity YAML. Change the `x-cortex-type` field in the entity's YAML descriptor to the new type. This can only be done via YAML, not through the UI.

A **Cannot change the type of the entity** error means the **Enable changing entity type** option is disabled. Turn it on to allow the change. See the prerequisite section above.

{% hint style="info" %}
Deleted entities can be re-created with a different type, regardless of this setting.
{% endhint %}

#### Viewing relationship types

Software ecosystems are rarely flat. Services depend on each other, teams own different parts of the stack, and domains nest inside larger business areas. Relationship types let you capture these connections in Cortex, so your catalog reflects how your organization actually fits together.

A relationship type defines how two entities relate to one another and which entity types are allowed as the source and destination of that relationship. Cortex supports a few different ways to model these connections:

* **Entity relationships** - Custom relationships you define between any entity types, either hierarchical or cyclical.
* **Team hierarchies** - Hierarchical relationships between team entities, including ownership over other entities.
* **Domain hierarchies** - Hierarchical relationships between domain entities, with optional ownership inheritance from higher levels of the hierarchy.
* **Dependencies** - Cyclical relationships between non-team entities, used to model how services and resources rely on each other.

Together, these relationship types give you a flexible way to represent both the structural and operational connections across your workspace.

To view all relationship types, expand **Catalogs** in the main sidebar and select **All entities**. Select the **Relationship types** tab.

<div align="left" data-with-frame="true"><figure><img src="/files/s7cIjPOsjfWXWK2WDCRe" alt="&#x27;Relationship types&#x27; tab in Cortex showing the list of defined entity relationships" width="563"><figcaption></figcaption></figure></div>

See [Defining relationship types](/ingesting-data-into-cortex/entities-overview/entities/defining-relationship-types) for more information.

## Archiving entities

Entities can be deleted outright, but archiving is often the better choice as it removes entities from active use while preserving them for historical reference.

For hands-off maintenance, [configure auto-archival](/ingesting-data-into-cortex/entities-overview/entities/archiving-entities/auto-archive) to automatically archive entities when they're no longer detected in your integrations or when their YAML files are deleted. Entities can also be archived manually through the Cortex UI or API. See [Archiving entities](/ingesting-data-into-cortex/entities-overview/entities/archiving-entities).


# Defining entities with YAML

Every entity in your Cortex catalog is defined by a YAML file called the Cortex entity descriptor—often referred to as an entity's *Cortex YAML*, after the `cortex.yaml` filename used in the GitOps approach. This applies whether you manage entities through the UI or GitOps; the descriptor is the underlying source of truth either way.

Each descriptor is a fully compliant OpenAPI 3 spec file, extended with Cortex-specific fields that unlock additional functionality in your catalog.

{% hint style="info" %}
You don't need to use OpenAPI or Swagger to use Cortex. The OpenAPI spec serves as the foundation for entity metadata because it's an open standard with official support for extensions, allowing Cortex to extend it into a full entity descriptor spec, while keeping the actual OpenAPI fields optional.
{% endhint %}

## Metadata in entity descriptor YAML files

You can extend an entity by adding metadata to the `info` section of its descriptor. Throughout the docs, you'll see snippets prefixed with `x-cortex-*`; these are descriptor blocks that belong inside `info` and unlock additional Cortex functionality.

{% hint style="info" %}
YAML comments aren't supported in entity descriptors. Cortex stores descriptors as JSON in the database, and JSON doesn't support comments. Most YAML parsers also strip comments during round-tripping, so any comments added to a descriptor will be lost.
{% endhint %}

### Required blocks

Every entity YAML requires the following:

<table><thead><tr><th width="140.765625">Block</th><th>Description</th></tr></thead><tbody><tr><td><code>title</code></td><td>The name of the entity</td></tr><tr><td><code>x-cortex-tag</code></td><td>The <a href="#entity-tag">unique identifier for the entity</a></td></tr><tr><td><code>x-cortex-type</code></td><td><p>The <a href="#entity-types">entity type</a><br></p><ul><li>If the entity is a <a href="/pages/0BEkeCNaXgSo20PlGcRo#create-custom-entities-in-the-entity-descriptor">custom type</a>, you must also include <code>x-cortex-definition</code></li></ul></td></tr></tbody></table>

### **Recommended blocks**

Although they aren't required, it's strongly recommended to add a description, groups, and owners:

<table><thead><tr><th width="180.3984375">Block</th><th>Definition</th></tr></thead><tbody><tr><td><code>description</code></td><td>A description of the entity</td></tr><tr><td><code>x-cortex-groups</code></td><td><p>The entity's <a href="/pages/ruG8CemqPJPUPiLhd1o8">groups</a> - a tagging system used to segment entities<br></p><ul><li>Required field - <code>tag</code></li></ul></td></tr><tr><td><code>x-cortex-owners</code></td><td><p>The entity's <a href="/pages/6xb6CNWMMEBjwTqIzzlQ#assigning-ownership-via-an-entity-descriptor">owners</a><br></p><ul><li><p>Required field(s) - <code>type</code>, which can be <code>group</code> or <code>email</code></p><ul><li>For <code>group</code> owners, <code>name</code> and <code>provider</code> are also required. The <code>provider</code> value is the integration the group comes from; use <code>CORTEX</code> for a team defined in Cortex.</li><li>For <code>email</code> owners, <code>email</code> is also required</li></ul></li><li><code>inheritance</code> - When creating a domain entity and adding owners to it, or while creating an entity relationship, you can set <a href="/pages/6xb6CNWMMEBjwTqIzzlQ#assigning-ownership-via-an-entity-descriptor">ownership inheritance</a> under this block to pass down to the entity's children. The inheritance type can be <code>APPEND</code>, <code>FALLBACK</code>, or <code>NONE</code>.</li></ul></td></tr></tbody></table>

### **Additional basic metadata blocks**

<table><thead><tr><th width="179.90625">Block</th><th>Definition</th></tr></thead><tbody><tr><td><code>x-cortex-custom-metadata</code>:</td><td><p>The entity's <a href="/pages/0pawHMQrFlZ2APpwlqa3">custom data</a><br></p><ul><li>Required fields - a key, <code>value</code>, and <code>description</code>. The key is the title for the custom data.</li></ul></td></tr><tr><td><code>x-cortex-dependency</code></td><td><p>The entity's <a href="/pages/lriEpowNUcQfWez9QDDX">dependencies</a><br></p><ul><li>Required fields - <code>tag</code>. If <code>method</code> is included, then <code>path</code> is also required.</li></ul></td></tr><tr><td><code>x-cortex-link</code></td><td><a href="/pages/5cEJd1jQZq1Shqjz7YAg">Documentation links</a> associated with the entity: <code>name</code>, <code>type</code>, and <code>url</code></td></tr><tr><td><code>x-cortex-parents</code> and <code>x-cortex-children</code></td><td><p>The entity's parent entities and children entities<br></p><ul><li>Required field - <code>tag</code></li><li>These fields are supported for entities that are members of a <a href="/pages/PVRYqXSfutvMjgCZhp3F#understanding-relationship-types-in-cortex">hierarchical entity relationship</a>, such as domains or teams</li></ul></td></tr><tr><td><code>x-cortex-relationships</code></td><td><p>A block that includes the entity's <a href="/pages/PVRYqXSfutvMjgCZhp3F#entity-descriptor">relationship type and destination entities</a><br></p><ul><li>Required fields - <code>type</code> and <code>destinations</code></li></ul></td></tr><tr><td><code>x-cortex-team</code></td><td><p>This appears in a <a href="/pages/k2dYsILMpH9zFdKGLhRj#entity-descriptor">team entity's YAML</a>. <code>members</code> can be defined under this block.<br></p><ul><li>A <code>member</code> is defined by <code>name</code> and <code>email</code>, and can also include <code>notificationsEnabled</code> and <code>roles</code>.</li></ul></td></tr></tbody></table>

### **Integration metadata blocks**

See the related linked documentation pages for instructions on adding metadata within each type of block.

<table><thead><tr><th width="247.8125">Block</th><th></th></tr></thead><tbody><tr><td><code>x-cortex-alerts</code></td><td><a href="/pages/JEvChnD825Dk6Byn1mog">Opsgenie</a></td></tr><tr><td><code>x-cortex-apiiro</code></td><td><a href="/pages/rKjGunK2MAdxgaELbtSW">Apiiro</a></td></tr><tr><td><code>x-cortex-apm</code></td><td><a href="/pages/kRWtggFQYYp6FS6DzgLk">Datadog</a>, <a href="/pages/uOMTxgC5zj2oFsWsoXcq">Dynatrace</a>, <a href="/pages/3J3rOtgnvKCFiglcfy1O">New Relic</a></td></tr><tr><td><code>x-cortex-azure</code></td><td><a href="/pages/dLCbw5E6LxK8D3yCJCYD">Azure Resources</a></td></tr><tr><td><code>x-cortex-azure-devops</code></td><td><a href="/pages/UfaVrLl3RKIMq5MfGl8t">Azure DevOps</a></td></tr><tr><td><code>x-cortex-bugsnag</code></td><td><a href="/pages/o8Lte9uCwNidfXDXdtAc">BugSnag</a></td></tr><tr><td><code>x-cortex-ci-cd</code></td><td><a href="/pages/jGrBfRxtPPcGz3DNdZcs">Buildkite</a></td></tr><tr><td><code>x-cortex-checkmarx</code></td><td><a href="/pages/YApHGr8JiWQIwelMxuA7">Checkmarx</a></td></tr><tr><td><code>x-cortex-circle-ci</code></td><td><a href="/pages/SAZ8GgdTpdVOKEuuP3kU">CircleCI</a></td></tr><tr><td><code>x-cortex-coralogix</code></td><td><a href="/pages/B4Sw6S0xL3yKUhs5flhn">Coralogix</a></td></tr><tr><td><code>x-cortex-dashboards</code></td><td>Charts embedded from <a href="/pages/kRWtggFQYYp6FS6DzgLk">Datadog</a>, <a href="/pages/wc7RqyD55GDSaxYUmu8f">Grafana</a>, or <a href="/pages/3J3rOtgnvKCFiglcfy1O">New Relic</a></td></tr><tr><td><code>x-cortex-firehydrant</code></td><td><a href="/pages/rxkq9NIP59CbOPbVOe7p">FireHydrant</a></td></tr><tr><td><code>x-cortex-git</code></td><td><a href="/pages/UfaVrLl3RKIMq5MfGl8t">Azure DevOps</a>, <a href="/pages/kGrYUNlQZ02lIZkLr9GB">Bitbucket</a>, <a href="/pages/Xk8Sl5l7hncSwE0jkSC5">GitHub</a>, <a href="/pages/WW79Lsssh71ec7TlH7L2">GitLab</a></td></tr><tr><td><code>x-cortex-incident-io</code></td><td><a href="/pages/ZxMuzQi9AvvPGuN8njG5">incident.io</a></td></tr><tr><td><code>x-cortex-infra</code></td><td><a href="/pages/IpplVfBAjkvV30wggOAV">AWS</a>, <a href="/pages/lgZ9FTSqYCAkvTxVKYnR">Google</a></td></tr><tr><td><code>x-cortex-issues</code></td><td><a href="/pages/F0YEYLHAXU4ne0S0bb66">ClickUp</a>, <a href="/pages/Xk8Sl5l7hncSwE0jkSC5">GitHub</a>, <a href="/pages/hzJxJGhFlJtRBS9bw0ZM">Jira</a></td></tr><tr><td><code>x-cortex-k8s</code></td><td><a href="/pages/dLo7cW1bb9JvK7AJ9imS">Kubernetes</a></td></tr><tr><td><code>x-cortex-launch-darkly</code></td><td><a href="/pages/qCf8Um88KkPrjrn4hQSb">LaunchDarkly</a></td></tr><tr><td><code>x-cortex-microsoft-teams</code></td><td><a href="/pages/eA83dZvRK3iwWEE2NAJI">Microsoft Teams channels</a></td></tr><tr><td><code>x-cortex-oncall</code></td><td><a href="/pages/XDAUWFsDegInAZMY2ucB">PagerDuty</a>, <a href="/pages/uNmFSzHYVZklPYzhpikK">Splunk On-Call (VictorOps)</a>, <a href="/pages/sQYZHpisDx2OjQLnsP4A">xMatters</a></td></tr><tr><td><code>x-cortex-owners</code></td><td>When you specify <code>group</code> as the <code>type</code>, you can use the following integrations as the group <code>provider</code>: <a href="/pages/sezVtfvNGVEsZKLfOF2R">BambooHR</a>, <a href="/pages/kGrYUNlQZ02lIZkLr9GB">Bitbucket</a>, <a href="/pages/80JEbVo15jgcPcgvHwAZ">Entra ID (Azure AD)</a>, <a href="/pages/Xk8Sl5l7hncSwE0jkSC5">GitHub</a>, <a href="/pages/WW79Lsssh71ec7TlH7L2">GitLab</a>, <a href="/pages/lgZ9FTSqYCAkvTxVKYnR">Google</a>, <a href="/pages/jDIzrDn5NdqO33h6mzhy">Okta</a>, <a href="/pages/X7U6BovNifbqhXexFPxc">ServiceNow</a>, <a href="/pages/a13EpqM8gbXz8YVtYdvQ">Workday</a></td></tr><tr><td><code>x-cortex-rollbar</code></td><td><a href="/pages/ZHZIhHXr3KApkpZLigCU">Rollbar</a></td></tr><tr><td><code>x-cortex-rootly</code></td><td><a href="/pages/GmV26i9AeWtrz4VhaYwA">Rootly</a></td></tr><tr><td><code>x-cortex-sentry</code></td><td><a href="/pages/o0004rWtddFomLBsE48C">Sentry</a></td></tr><tr><td><code>x-cortex-semgrep</code></td><td><a href="/pages/HPYngZSFHEXMw12TF7I7">Semgrep</a></td></tr><tr><td><code>x-cortex-servicenow</code></td><td><a href="/pages/X7U6BovNifbqhXexFPxc">ServiceNow</a></td></tr><tr><td><code>x-cortex-slack</code></td><td><a href="/pages/E9axggeqAgqwSbjpIcUo">Slack channels</a></td></tr><tr><td><code>x-cortex-slos</code></td><td><a href="/pages/kRWtggFQYYp6FS6DzgLk">Datadog</a>, <a href="/pages/uOMTxgC5zj2oFsWsoXcq">Dynatrace</a>, <a href="/pages/lgZ9FTSqYCAkvTxVKYnR">Google</a>, <a href="/pages/RugXMwlZGeHNPfMTgavQ">Lightstep</a>, <a href="/pages/d5OW1jvVwAunmNp13nev">Prometheus</a>, <a href="/pages/YBtg2KsyFV3h411WSLOM">Splunk Observability Cloud (SignalFX)</a>, <a href="/pages/3MKMPLhBvPysG16IA7J3">Sumo Logic</a></td></tr><tr><td><code>x-cortex-snyk</code></td><td><a href="/pages/0dP78PbdmjrvRRBeFPsD">Snyk</a></td></tr><tr><td><code>x-cortex-static-analysis</code></td><td><a href="/pages/w9uMZxXgz3ZoMWzgiYXU">Codecov</a>, <a href="/pages/1Em0Q803ZImnzlIZfkxj">Mend</a>, <a href="/pages/LlpzID94xzZSAvmVKzFJ">SonarQube</a>, <a href="/pages/qgZciFiMo6NiLzGBjeW0">Veracode</a></td></tr><tr><td><code>x-cortex-wiz</code></td><td><a href="/pages/u7Q3UvY6KoFYL9TbRD8i">Wiz</a></td></tr></tbody></table>

## Example entity YAML

The example below demonstrates how you can use each of the blocks in an entity's YAML.

```yaml
## API Spec and Version
openapi: 3.0.0

# Service Descriptors
# Required fields: info, title, x-cortex-tag
info:
  title: Payments API
  x-cortex-tag: payments-api
  description: Handles payment processing, refunds, and transaction history for the Cortex platform.

  # Groups
  # !Groups must contain only alphanumeric characters, and may not contain whitespaces!
  x-cortex-groups:
    - backend
    - payments
    - us-west

  # Owners
  x-cortex-owners:
    - type: group
      name: platform-engineering
      provider: CORTEX # Use when referring to a team defined in Cortex; these teams do not map to identities from integrations
      description: Core platform team responsible for payments infrastructure
    - type: email
      email: backend-oncall@cortex.io
      description: On-call rotation for backend services
    - type: group
      name: cortexapps/backend-platform
      provider: ACTIVE_DIRECTORY | AZURE_DEVOPS | BAMBOO_HR | GITHUB | GITLAB | GOOGLE | OKTA | OPSGENIE | SERVICE_NOW | WORKDAY
  # Also see the team entity example below

  # Links
  x-cortex-link:
    - name: API Reference
      type: OPENAPI
      url: https://api.cortex.io/payments/openapi.yaml
      description: OpenAPI spec for the Payments API
    - name: Runbook
      type: DOCUMENTATION
      url: https://cortex.atlassian.net/wiki/spaces/ENG/pages/payments-api-runbook
      description: Operational runbook for incidents and deployments
  ## Note that type of OPENAPI/ASYNC_API will be displayed in the API Explorer tab in the Cortex UI
  ## Links support relative URLs

  # Dashboards
  x-cortex-dashboards:
    embeds:
      - type: datadog
        url: https://app.datadoghq.com/dashboard/abc-123-xyz/payments-api-overview

  # Custom Data
  x-cortex-custom-metadata:
    tier: tier-1
    language:
      value: go
      description: Primary implementation language
    pci-compliant:
      value: true
      description: Service is in scope for PCI DSS compliance
    on-call-schedule:
      - platform-engineering
      - backend-sre

  # Custom entities
  # You cannot create a custom entity type via GitOps, but after creating the type in the UI or API, you can create custom entities via GitOps.
  title: Alex Rivera
  description: Senior Platform Engineer
  x-cortex-tag: employee-alex-rivera
  x-cortex-type: org-employees
  x-cortex-definition:
    location: San Francisco
    department: Platform Engineering

  # Parent and child relationships
  x-cortex-type: team
  x-cortex-children:
    - tag: payments-frontend-team
    - tag: payments-backend-team

  x-cortex-type: domain
  x-cortex-parents:
    - tag: engineering-domain
    - tag: fintech-domain

  # Entity relationships
  x-cortex-relationships:
    - type: depends-on
      destinations:
        - tag: fraud-detection-service
        - tag: ledger-service

  # Dependencies
  # Required fields: x-cortex-tag, method (required if path present), path (required if method present)
  x-cortex-dependency:
    - tag: fraud-detection-service
      method: POST
      path: /v1/evaluate
      description: Evaluates transactions for fraud signals before processing
      metadata:
        tags:
          - payments
          - fraud
        prod: true

# Team configurations
title: Platform Engineering
x-cortex-tag: platform-engineering
x-cortex-type: team
x-cortex-team:
  groups:
    - name: platform-engineering
      provider: OKTA
  members:
    - name: Jordan Lee
      email: jordan.lee@cortex.io
      notificationsEnabled: true
    - name: Samantha Dawson
      email: samantha.dawson@cortex.io
      notificationsEnabled: false
x-cortex-children:
  - tag: infra-team
  - tag: sre-team

# Domain configurations
x-cortex-type: domain
x-cortex-owners:
  - type: GROUP
    name: cortexapps/engineering
    provider: GITHUB
    inheritance: APPEND | FALLBACK | NONE
x-cortex-children:
  - tag: payments-api
  - tag: payments-database

# Integrations

# Apiiro
x-cortex-apiiro:
  repositories:
    - alias: payments-api
      repositoryId: cortexapps-payments-api
    - alias: payments-worker
      repositoryId: cortexapps-payments-worker
  applications:
    - alias: payments-api-app
      applicationId: app-payments-api-prod
    - alias: payments-worker-app
      applicationId: app-payments-worker-prod

# AWS Cloud Control types
x-cortex-infra:
  aws:
    cloudControl:
      - type: AWS::RDS::DBInstance
        region: us-west-2
        accountId: "123456789012"
        identifier: payments-db-prod

# AWS ECS
x-cortex-infra:
  aws:
    ecs:
      - clusterArn: arn:aws:ecs:us-west-2:123456789012:cluster/prod-cluster
        serviceArn: arn:aws:ecs:us-west-2:123456789012:service/prod-cluster/payments-api
      - clusterArn: arn:aws:ecs:us-east-1:123456789012:cluster/prod-cluster-east
        serviceArn: arn:aws:ecs:us-east-1:123456789012:service/prod-cluster-east/payments-api

# Azure DevOps
x-cortex-git:
  azure:
    project: cortex-platform
    repository: payments-api

# Azure Resources
x-cortex-azure:
  ids:
    - id: /subscriptions/1fbb2da1-2ce7-45e4-b85f-676ab8e12345/resourceGroups/payments-prod/providers/Microsoft.Compute/disks/payments-db-disk
      alias: payments-prod-disk # alias is optional and only relevant if you have opted into multi account support
    - id: /subscriptions/1fbb2da1-2ce8-45e4-b85f-676ab8e12345/resourceGroups/payments-staging/providers/Microsoft.Compute/disks/payments-db-disk-staging
      alias: payments-staging-disk # alias is optional and only relevant if you have opted into multi account support

# BambooHR
x-cortex-owners:
  - type: group
    name: Platform Engineering
    provider: BAMBOO_HR
    description: # optional

# Bitbucket
x-cortex-git:
  bitbucket:
    repository: cortexapps/payments-api
x-cortex-owners:
  - type: group
    name: platform-engineering
    provider: BITBUCKET
    description: # optional

# Bugsnag
x-cortex-bugsnag:
  project: payments-api-prod

# Buildkite
x-cortex-ci-cd:
  buildkite:
    pipelines:
      - slug: payments-api-build
      - slug: payments-api-deploy
    tags:
      - tag: payments
      - tag: backend

# Checkmarx
x-cortex-checkmarx:
  projects:
    - projectName: payments-api
    - projectId: 8821

# CircleCI
x-cortex-circle-ci:
  projects:
    - projectSlug: gh/cortexapps/payments-api
      alias: payments-api-circleci # alias is optional and only relevant if you have opted into multi account support

# ClickUp
x-cortex-issues:
  clickup:
    spaces:
      - identifier: 987654321
        identifierType: ID
    folders:
      - identifier: Platform Engineering
        identifierType: NAME
    tags:
      - name: payments
      - name: backend

# Codecov
x-cortex-static-analysis:
  codecov:
    owner: cortexapps
    repo: payments-api
    provider: AZURE_DEVOPS | BITBUCKET | BITBUCKET_SERVER | GITHUB | GITHUB_ENTERPRISE | GITLAB | GITLAB_ENTERPRISE
    flag: unit

# Coralogix
x-cortex-coralogix:
  applications:
    - applicationName: payments-api
      alias: payments-prod # alias is optional and only relevant if you have opted into multi account support
    - applicationName: payments-worker
      alias: payments-worker-prod # alias is optional and only relevant if you have opted into multi account support

# Datadog
x-cortex-apm:
  datadog:
    serviceTags: # List of tags & values
      - tag: service
        value: payments-api
      - tag: env
        value: prod
    serviceName: payments-api
    monitors:
      - 12345678
      - 12345679
x-cortex-slos:
  datadog: # List of SLO ids
    - id: abc123def456ghi7
    - id: xyz789uvw012rst3

# Dynatrace
x-cortex-apm:
  dynatrace:
    entityIds:
      - SERVICE-A1B2C3D4E5F60001
      - SERVICE-A1B2C3D4E5F60002
    entityNameMatchers:
      - "payments.*"
x-cortex-slos:
  dynatrace:
    - id: slo-payments-availability
    - id: slo-payments-latency

# Entra ID (Azure Active Directory)
x-cortex-owners:
  - type: group
    name: platform-engineering
    provider: ACTIVE_DIRECTORY
    description: # optional

# FireHydrant
x-cortex-firehydrant:
  services:
    - identifier: PYMT1234
      identifierType: ID
    - identifier: payments-api
      identifierType: SLUG

# GitHub
x-cortex-git:
  github:
    repository: cortexapps/payments-api
    basepath: payments-api # optional
x-cortex-owners:
  - type: group
    name: cortexapps/backend-platform # Must be of form <org>/<team>
    provider: GITHUB
    description: Backend platform team

# GitLab
x-cortex-git:
  gitlab:
    repository: cortexapps/platform/payments-api
    basepath: payments-api # optional
x-cortex-owners:
  - type: group
    name: Platform Engineering
    provider: GITLAB
    description: Core platform team for payments infrastructure

# Google
x-cortex-owners:
  - type: group
    name: platform-engineering@cortex.io
    provider: GOOGLE
x-cortex-dependency:
  gcp:
    labels:
      - key: service
        value: payments-api
      - key: env
        value: prod
x-cortex-infra:
  Google Cloud:
    resources:
      - resourceName: us-central1/payments-processor-fn
        projectId: cortex-platform-prod
        resourceType: function
      - resourceName: payments-assets-prod
        projectId: cortex-platform-prod
        resourceType: storage
x-cortex-slos:
  gcp:
    - projectId: cortex-platform-prod
      serviceId: iLE2e4HvR_PaymentsAPI01
    - projectId: cortex-platform-prod
      serviceId: iLE2e4HvR_PaymentsWorker01

# Grafana
x-cortex-dashboards:
  embeds:
    - type: grafana
      url: https://grafana.cortex.io/d/abcd1234/payments-api-overview

# incident.io
x-cortex-incident-io:
  customFields:
    - name: Service
      value: Payments API
      alias: payments-prod
    - id: payments-worker-id
      value: payments-worker
      alias: payments-worker-prod

# Jira
x-cortex-issues:
  jira:
    labels:
      - payments
      - backend
    components:
      - api-gateway
    projects:
      - PLAT
      - PAY
    # Optional: Override Cortex default Jira query
    defaultJql: 'project = PAY AND status = "In Progress" AND labels = "payments"'

# Kubernetes
x-cortex-k8s:
  deployment:
    - identifier: payments/payments-api
      cluster: prod-us-west-2 # optional
    - identifier: payments/payments-api
      cluster: staging
    - identifier: default/payments-api
      cluster: prod-us-east-1
  argorollout:
    - identifier: payments/payments-api-canary
      cluster: prod-us-west-2
  statefulset:
    - identifier: payments/payments-db-replica
      cluster: prod-us-west-2
  cronjob:
    - identifier: payments/payments-reconciler
      cluster: prod-us-west-2

# LaunchDarkly
x-cortex-launch-darkly:
  projects:
    - key: payments-platform
      environments: # Optional
        - environmentName: prod
        - environmentName: staging
      alias: payments-ld-prod # alias is optional and only relevant if you have opted into multi account support
    - tag: backend-services
      environments: # Optional
        - environmentName: prod
      alias: backend-ld-prod # alias is optional and only relevant if you have opted into multi account support
  feature-flags:
    - tag: payments-rollout
      environments: # Optional
        - environmentName: staging
      alias: payments-flags-staging # alias is optional and only relevant if you have opted into multi account support

# Lightstep
x-cortex-slos:
  lightstep:
    - streamId: AbCdEfGhIjKlMnOp
      targets:
        latency:
          - percentile: 0.99
            target: 200
            slo: 0.999

# Mend
x-cortex-static-analysis:
  mend:
    applicationIds:
      - payments-api-mend
      - payments-worker-mend
    projectIds:
      - cortexapps_payments-api
      - cortexapps_payments-worker

# Microsoft Teams
x-cortex-microsoft-teams:
  channels:
    - name: payments-engineering
      teamName: Platform Engineering
      description: Channel for payments engineering discussions and alerts.
      notificationsEnabled: true

# New Relic
x-cortex-apm:
  newrelic:
    applications:
      - applicationId: 987654321
        alias: payments-api-prod
    tags:
      - tag: service
        value: payments-api
        alias: payments-api-prod
x-cortex-dashboards:
  embeds:
    - type: newrelic
      url: https://one.newrelic.com/dashboards/abc123def456-payments-api

# While the `applications` wrapper format is the recommended format, Cortex also supports a flat array format:
# x-cortex-apm:
#   newrelic:
#     - applicationId: 987654321

# Okta
x-cortex-owners:
  - type: group
    name: platform-engineering # group name in Okta
    provider: OKTA
    description: # optional

# OpsGenie
x-cortex-oncall:
  opsgenie:
    type: SCHEDULE
    id: a1b2c3d4-e5f6-7890-abcd-ef1234567890 # Optionally, can use the Rotation UUID instead
x-cortex-owners:
  - type: group
    name: platform-engineering
    provider: OPSGENIE
    description: # optional
x-cortex-alerts:
  - type: opsgenie
    tag: service
    value: payments-api

# PagerDuty
x-cortex-oncall:
  pagerduty:
    id: P1A2B3C # Service ID
    type: SERVICE
x-cortex-oncall:
  pagerduty:
    id: S4D5E6F # Schedule ID
    type: SCHEDULE
x-cortex-oncall:
  pagerduty:
    id: E7G8H9I # Escalation Policy ID
    type: ESCALATION_POLICY

# Prometheus
x-cortex-slos:
  prometheus:
    - errorQuery: sum(rate(http_requests_total{service="payments-api",status=~"5.."}[5m]))
      totalQuery: sum(rate(http_requests_total{service="payments-api"}[5m]))
      slo: 0.999
      alias: payments-prometheus
      name: payments-api-availability

# Rollbar
x-cortex-rollbar:
  project: payments-api

# Rootly
x-cortex-rootly:
  services:
    - id: PYMT5678
    - slug: payments-api

# Sentry
x-cortex-sentry:
  projects:
    - name: payments-api
    - name: payments-worker

# Semgrep
x-cortex-semgrep:
  projects:
    - alias: cortexapps
      projectId: 1122334
    - alias: cortexapps-oss
      projectId: 4433221

# ServiceNow
x-cortex-servicenow:
  services:
    - tableName: cortex-platform-services
      id: 42
x-cortex-owners:
  - type: group
    name: Platform Engineering
    provider: SERVICE_NOW
    description: Primary team responsible for payments infrastructure # optional

# Slack
x-cortex-slack:
  channels:
    - id: C04ABCDE123
      notificationsEnabled: true
      description: Payments team channel for engineering discussions
    - name: payments-alerts
      notificationsEnabled: true
      description: Automated alerts channel for the Payments API

# Snyk
x-cortex-snyk:
  projects:
    - organizationId: a1b2c3d4-e5f6-7890-abcd-ef1234567890
      projectId: f0e9d8c7-b6a5-4321-fedc-ba9876543210
      source: CODE

# SonarQube
x-cortex-static-analysis:
  sonarqube:
    project: cortexapps_payments-api
    alias: payments-sonar

# Splunk Observability Cloud (SignalFX)
x-cortex-slos:
  signalfx:
    - query: 'sf_metric:"request.latency" AND service:"payments-api"'
      rollup: AVERAGE
      target: 200
      lookback: 3600000
      operation: BELOW

# Splunk On-Call (VictorOps)
x-cortex-oncall:
  victorops:
    type: SCHEDULE
    id: platform-engineering-24x7

# Sumo Logic
x-cortex-slos:
  sumologic:
    - id: 000000000001001
    - id: 000000000001002

# Veracode
x-cortex-static-analysis:
  veracode:
    applicationNames:
      - Payments API
      - Payments Worker
    sandboxes:
      - applicationName: Payments API
        sandboxName: payments-api-staging
      - applicationName: Payments Worker
        sandboxName: payments-worker-staging

# Wiz
x-cortex-wiz:
  projects:
    - projectId: 9a8b7c6d-e5f4-3210-abcd-ef1234567890

# Workday
x-cortex-owners:
  - type: group
    name: platform-engineering
    provider: CORTEX
    description: Platform Engineering team in Workday org structure

# xMatters
x-cortex-oncall:
  xmatters:
    id: platform-engineering-oncall
    type: SERVICE
```


# YAML linter tool

The Cortex YAML linter validates your `cortex.yaml` files against both general YAML syntax and Cortex-specific schema requirements, catching invalid or incomplete entity definitions before they reach the platform.

This page covers the built-in tool available in the Cortex UI under **Tools > YAML Linter**. A separate linter is also built into the Cortex GitHub app, which runs checks on pull requests when you use GitHub in a [GitOps workflow](/configure/gitops).

## Using the YAML linter

### Validating a YAML file in the Cortex UI

1. From the main sidebar, expand **Tools**, then select **YAML linter**.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/8Csf7gbTKcJnPtAPQ0AW" alt="The YAML linter tool displayed in the Cortex UI." width="375"><figcaption></figcaption></figure></div>
2. Paste your YAML into the text editor, then click **Validate YAML**.
3. A status banner appears at the bottom of the page:
   * If the format is valid, a success message is displayed:

     <div align="left" data-with-frame="true"><figure><img src="/files/0UcjjVlYfTZF9KHBIXgA" alt="Valid YAML success icon and message."><figcaption></figcaption></figure></div>
   * If the format is incorrect:
     * For issues with the format of a Cortex-specific block, a warning banner appears:

       <div align="left" data-with-frame="true"><figure><img src="/files/PKCsd1r1G3ST1Ytagd2g" alt="The linter warning banner indicates that x-cortex-apm has an empty value in the YAML file."><figcaption></figcaption></figure></div>
     * For errors that cause the YAML to fail the linter check (such as missing a `title` or `x-cortex-tag`), a failure banner that includes the error message and which line is affected appears:

       <div align="left" data-with-frame="true"><figure><img src="/files/8RiohgjQ5tr9MB1uu8ht" alt="YAML fail icon and message."><figcaption></figcaption></figure></div>

### Validation scope

The linter checks for valid YAML structure and ensures required Cortex fields (like `openapi` version, `x-cortex-tag`, etc.) are present. If a required field is not present, this results in an error and the YAML does not pass the linter check.

The linter also validates the format of Cortex-specific blocks (e.g., `x-cortex-groups`, `x-cortex-firehydrant`) but does not verify the correctness of referenced data (such as whether a group or monitor ID actually exists). If there is an issue for a Cortex block, such as a block that doesn't contain a value, you will see a warning; however, the YAML will still pass the linter check.

If you submit a file with templating syntax (e.g., Jinja or cookiecutter variables like `{{ variable }}`), the linter will fail because these are not valid YAML until rendered. Only fully rendered YAML files will pass validation.

If the YAML is invalid or missing required fields, the linter will return errors indicating the line and nature of the problem.

### GitOps settings for the linter tool

If you are using GitHub in a GitOps workflow, you can adjust settings related to the linter. See [GitOps Settings](/configure/settings/gitops-settings) for more information.


# Adding entities

Entities are the foundational building blocks that represent the components of your software ecosystem—services, domains, teams, and more—giving your organization a shared way to describe what exists and how it connects. Defined in YAML and enriched with live data from your existing tools, entities come together to form a catalog that serves as a single source of truth.

Cortex provides a set of built-in entity types that cover the most common building blocks of a software organization. These defaults give you a strong foundation out of the box, so you can start cataloging your ecosystem without needing to design a schema from scratch.

Learn how to add built-in entity types and how to create your own custom entity types in the sections below:

* [Services](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/add-services)
* [Domains](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/domains)
* [Teams](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/teams)
* [Custom entity types](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/entity-types)
* [Define dependencies](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/dependencies)

{% hint style="success" %}
Want to learn more? Check out the Cortex Academy course on [Catalogs, Entities, and Relationships](https://academy.cortex.io/courses/understanding-understanding-catalogs-entities-and-relationships).
{% endhint %}


# Adding services

Services are a default entity type in Cortex used to represent the codebase-like modules that make up your software ecosystem—microservices, libraries, components, etc. All entity types in Cortex, including services, are defined by a `cortex.yaml` file, which declares the entity's identity, ownership, dependencies, and links to the tools that support it (CI/CD, observability, on-call, documentation, and more). Once defined, a service becomes a first-class entity in your catalog, automatically enriched with live data pulled from your integrations.

Services are typically the most numerous entity type in a catalog and the closest match to how engineering teams already think about their work: as discrete units of code that do something specific, owned by someone, deployed somewhere, and depended on by other things. Modeling them consistently gives your organization a single place to answer questions that otherwise require digging through multiple tools—who owns this, what it depends on, whether it meets your standards, and where it runs. The result is a shared understanding that connects day-to-day engineering work to broader goals around quality, ownership, and operational maturity.

## Adding service entities to Cortex

Users with the `Edit Catalog` and `Edit Services` permissions can add service entities to Cortex.

When configuring an entity, you can't add archived teams as owners or archived entities as dependencies, parents, or children.

Services can be added manually, imported, defined in YAML via GitOps, or created via the API.

### Importing services from an integration

1. From the main sidebar, expand **Catalogs**, then select **All entities**.
2. In the upper-right corner, click **Import entities**.
3. Select **Import discovered entities**.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/gsAeItQRO7Q5luKuFTR1" alt="The &#x27;Import discovered entities&#x27; tile is displayed." width="363"><figcaption></figcaption></figure></div>
4. Select the integration to import from.\
   The **Select entities to import** page is displayed.
5. A list of entities from the integration are displayed. Select the checkboxes next to the entities you want to import. Use the search bar to find entities by name, or click the **Filter icon** in the upper-right corner of the results list to filter by entity type. For Azure DevOps integrations, you can also filter by project name. Search and filters run server-side, so they stay responsive even with large catalogs.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/7JhDfxcU1sxtpRo0UUNf" alt="" width="330"><figcaption></figcaption></figure></div>
6. In the bottom-right corner, click **Next step**.\
   The **Edit details** page is displayed.
7. Configure the following options. The options shown are filtered at runtime based on the `entityType` (e.g. 'Members' is team-only, 'Dependencies' excludes domains/teams) and whether the required integrations are enabled (e.g. 'Communications' requires Slack, 'On-call' requires Opsgenie/PagerDuty, etc.).
   1. From the **Type** drop-down menu, select **Service.**
   2. In the **Details** sectio&#x6E;**:**
      1. Under **Entity name**, enter a name for the entity (required).
      2. The **Cortex tag** field is auto-populated based on the name of the entity (required). It's a unique identifier for the entity. This is also known as the `x-cortex-tag`.
      3. Under **Description**, enter a description of the entity to help others understand its purpose.
      4. From the **Groups** drop-down men&#x75;**,** select a group or groups [to segment the entity](/ingesting-data-into-cortex/entities-overview/entities/groups).
   3. In the **Repository** section:
      1. From the **Provider** drop-down menu, select the repo provider.
      2. From the **Alias** drop-down menu, select the alias of the connected provider account that has access to the repository.
      3. From the **Repository** drop-down menu, select the repo associated with the entity. If you don't see it listed, click **Refresh repositories** to pull in the latest list.
      4. Under **Basepath**, enter the subdirectory within the repo where the entity's code lives. Leave blank if the entity occupies the entire repo.
   4. In the **Owners** section, define [ownership](/ingesting-data-into-cortex/entities-overview/entities/ownership) for the entity. Ownership can be assigned to either teams or individual users. It's recommended to select team owners to keep the ownership information up to date through any future personnel changes. To add a team or teams, click **Add** in the **Teams** area. To add an individual user or users, click **Add** in the **Users** area.
      * Cortex may recommend owners [based on repository activity](/ingesting-data-into-cortex/entities-overview/entities/ownership#recommendation). You can accept or reject the recommendations.
   5. In the **Links** section, click **Add** to add links to external documentation, such as runbooks, docs, logs, or custom categories.
   6. In the **Slack channels** section, click **Add** to link a Slack channel to the entity. If enabled, you'll receive notifications about the entity in the selected Slack channel.
   7. In the **Parents** section, select a parent domain or domains from the drop-down menu. This is where you configure the hierarchy for your entity, which can be visualized in the [relationship graph](/ingesting-data-into-cortex/entities-overview/entities/relationship-graph).
   8. In the **Dependencies** section, click **Add entity** to select an entity or entities that this entity depends on. These can be visualized in the [relationship graph](/ingesting-data-into-cortex/entities-overview/entities/relationship-graph).
8. If you selected more than one entity, click **Next entity** in the bottom-right corner of the page.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/wOtKl6Ln2jGVBCWTQiWh" alt="The &#x27;Next entity&#x27; link in the bottom-right corner of the page." width="375"><figcaption></figcaption></figure></div>
9. Click **Confirm import**.\
   The entity is imported into Cortex.

### Manually adding services

1. From the main sidebar, expand **Catalogs**, then select **All entities**.
2. In the upper-right corner, click **Import entities**.
3. Select **Create entities manually**.\
   The **Edit details** page is displayed.
4. Configure the following options. The options shown are filtered at runtime based on the `entityType` (e.g. 'Members' is team-only, 'Dependencies' excludes domains/teams) and whether the required integrations are enabled (e.g. 'Communications' requires Slack, 'On-call' requires Opsgenie/PagerDuty, etc.).
   1. From the **Type** drop-down menu, select **Service.**
   2. **In the Details section:**
      1. Below **Entity name**, enter a name for the entity (required).
      2. The **Cortex tag** field is auto-populated based on the name of the entity (required). Its a unique identifier for the entity. This is also known as the `x-cortex-tag`.
      3. Below **Description**, enter a description of the entity to help others understand its purpose.
      4. From the **Groups** drop-down men&#x75;**,** select a group or groups [to segment the entity](/ingesting-data-into-cortex/entities-overview/entities/groups).
   3. In the **Repository** section:
      1. From the **Provider** drop-down menu, select the repo provider.
      2. From the **Alias** drop-down menu, select the alias of the connected provider account that has access to the repository.
      3. From the **Repository** drop-down menu, select the repo associated with the entity. If you don't see it listed, click **Refresh repositories** to pull in the latest list.
      4. Below **Basepath**, enter the subdirectory within the repo where the entity's code lives. Leave blank if the entity occupies the entire repo.
   4. In the **Owners** section, define [ownership](/ingesting-data-into-cortex/entities-overview/entities/ownership) for the entity. Ownership can be assigned to either teams or individual users. It's recommended to select team owners to keep the ownership information up to date through any future personnel changes. To add a team or teams, click **Add** in the **Teams** area. To add an individual user or users, click **Add** in the **Users** area.
      * Cortex may recommend owners [based on repository activity](/ingesting-data-into-cortex/entities-overview/entities/ownership#recommendation). You can accept or reject the recommendations.
   5. In the **Links** section, click **Add** to add links to external documentation, such as runbooks, docs, logs, or custom categories.
   6. In the **Slack channels** section, click **Add** to link a Slack channel to the entity. If enabled, you'll receive notifications about the entity in the selected Slack channel.
   7. In the **Parents** section, select a parent domain or domains from the drop-down menu. This is where you configure the hierarchy for your entity, which can be visualized in the [relationship graph](/ingesting-data-into-cortex/entities-overview/entities/relationship-graph).
   8. In the **Dependencies** section, click **Add entity** to select an entity or entities that this entity depends on. These can be visualized in the [relationship graph](/ingesting-data-into-cortex/entities-overview/entities/relationship-graph).
5. Optionally, if you'd like to add another entity, click **Add entity** in the upper-right corner of the page.
6. Click **Confirm import**.\
   The entity is imported into Cortex. If there are any errors, a banner appears at the bottom of the page with the errors that need to be fixed.

### Adding a service in YAML via GitOps

Before creating a service entity via GitOps, be sure UI-based editing is disabled in Cortex. See [Managing entities via GitOps](/ingesting-data-into-cortex/entities-overview/entities#managing-entities-via-gitops).

**Service entity descriptor**

A blank spec file has the OpenAPI version, along with an `info` section that contains some basic details.

```yaml
openapi: 3.0.1
info:
  title: Account Service
  description: Manages user account lifecycle, authentication state, and organization membership. Used by the API gateway, billing service, and frontend clients.
  x-cortex-tag: account-service
  x-cortex-type: service
```

**Required fields**

The following fields are required under `info`: `title`, `x-cortex-tag`, and `x-cortex-type`. The description is optional, but highly recommended as a best practice.

<details>

<summary>Expand to see the example YAML</summary>

```yaml
openapi: 3.0.1
info:
  title: Chat Service
  description: Chat service is responsible for handling the chat feature.
  x-cortex-tag: chat-service
  x-cortex-type: service
  x-cortex-parents: # parents can be of type domain only
  - tag: notifications-domain
  - tag: support-domain
  x-cortex-groups:
  - python
  x-cortex-owners:
  - type: group
    name: Delta
    provider: OKTA
    description: Delta Team
  x-cortex-slack:
    channels:
    - name: delta-team
      notificationsEnabled: true
      description: This is a description for the delta-team Slack channel # optional
  x-cortex-link:
  - name: Chat ServiceAPI Spec
    type: OPENAPI
    url: ./docs/chat-service-openapi-spec.yaml
  x-cortex-custom-metadata:
    core-service: true
  x-cortex-dependency:
    - tag: authentication-service
    - tag: chat-database
  x-cortex-git:
    github:
      repository: org/chat-service
  x-cortex-oncall:
    pagerduty:
      id: ASDF1234
      type: SCHEDULE
  x-cortex-apm:
    datadog:
      monitors:
        - 12345
  x-cortex-issues:
    jira:
      projects:
        - CS
```

</details>

### Adding a service via the Cortex API

You can create, update, and delete services using the Cortex API. See [Catalog entities](/api/readme/catalog-entities) for more information.

## Viewing services

The **Services catalog** page lists every service entity that's been imported into Cortex. To open it, expand **Catalogs** in the main sidebar and select **Services**. Each row shows the entity's name and tag.

<div data-with-frame="true"><figure><img src="/files/arqg91oXKhvYVd7TU0Jd" alt="Overview of the Services page in the Cortex UI."><figcaption></figcaption></figure></div>

{% hint style="info" %}
Select the **All** tab to view all entities. Select the **Mine** tab to view only entities where you are an owner or member. Cortex saves your selection and restores it the next time you open this page.

<img src="/files/XPX1ltM1su6PpTkrfvfN" alt="" data-size="original">
{% endhint %}

### Searching across and filtering services

<div align="left" data-with-frame="true"><figure><img src="/files/AwOZoKbvLmnX3u6CKR39" alt="The search and filter options in the upper-right corner of the page."><figcaption></figcaption></figure></div>

There are several ways to search and filter your services list.

1. From the main sidebar, expand **Catalogs**, then select **Services.**
2. Do one of the following:
   * Select the **All** tab to search and filter across all of your organization's services.
   * Select the **Mine** tab to search and filter only the services you own.
   * Note that Cortex saves your selection and restores it the next time you open this page.
3. Do any or all of the following:
   * To find specific services, use the search bar in the upper-right corner of the page and type to search. The search bar shows which fields you can search on and which field your query is matching. For more information, see [Using search in Cortex](/configure/settings/search#using-the-catalog-search-bar).
   * Click **Name** to select whether you want to sort by name or identifier, and whether to sort by ascending or descending order.
   * Click **Display** to choose whether to show archived services in the list, and select which columns to display alongside services.
   * Click into a row to learn more about:
     * **Incidents** - Displays how many active incidents are associated with a given service. This information is pulled from FireHydrant, incident.io, PagerDuty, and Rootly.
     * **Health** - When you click into this column in an service's row, you can view more information about:
       * **Monitors** - Shows how services are performing against monitors you’ve created in your APM. When a service is passing all monitors, this cell will display `All OK`; otherwise, it displays `Failing`, `Warning`, or `No Data`, along with how many monitors the service is not hitting. This information is pulled from Datadog.
       * **Error rate** - Shows the percentage of transactions that result in a failure during a pre-specified window. This information is pulled from New Relic.
       * **Apdex (Application Performance Index)** - Ratio of the number of satisfied and tolerating requests to the total number requests made. This information is pulled from New Relic.<br>

         <div align="left" data-with-frame="true"><figure><img src="/files/9uAkJtwfj7iG0vPclWjs" alt="Shows the health and incidents columns on the entities page." width="304"><figcaption></figcaption></figure></div>
     * Columns that rely on an integration display **Not connected** when the integration hasn't been set up. If the integration is connected but the entity has no associated data or configuration, the cell displays **None** instead.
   * Click **Filter** to narrow down your list by by domain, entity type, group, owner, or team.

## Editing a service entity

Users with the `Edit Catalog` and `Edit Services` permissions can edit service entities.

Service entities can be modified at any time. Follow the steps below to edit a service entity.

1. Navigate to the entity's page.
2. In the upper-right corner, click **Configure entity**.\
   The entity details page opens.
3. In the upper-right corner, select either **UI editor** or **YAML editor**.
4. Make your changes. Note that the Cortex tag is uneditable.
5. Click **Save changes**.\
   The service entity is updated.

{% hint style="info" %}
It's possible to change the entity type via the Cortex YAML. See [Changing an entity's type](/ingesting-data-into-cortex/entities-overview/entities#changing-an-entitys-type) for more information.
{% endhint %}


# Adding domains

Domains are a default entity type in Cortex used to group entities into hierarchical units. You can group by product area, functionality, systems, business units, or something unique to your organization. With this feature, you can cluster entities into a single, hierarchical domain that can include both parents and children.

You can define a list of other entities as children for a domain, allowing you to represent a hierarchy of how your entities are modeled across your workspace. This hierarchy is available to view in the Domains catalog, on a domain entity's details page, and in the [relationship graph](/ingesting-data-into-cortex/entities-overview/entities/relationship-graph). The domain hierarchy can also be used to configure ownership inheritance, helping you keep track of ownership in case of personnel changes at your organization.

## Adding domain entities to Cortex

Users with the `Edit Catalog` and `Edit Domains` permissions can add domain entities to Cortex.

When configuring an entity, you can't add archived teams as owners or archived entities as dependencies, parents, or children.

Domains can be added manually, imported, defined in YAML via GitOps, or created via the API.

For simplicity, it's recommended to add the highest-level domain first, then select it as the parent for subsequent domains. However, you can add parents and children to any domain at any point.

### Importing domains from an integration

1. From the main sidebar, expand **Catalogs**, then select **All entities**.
2. In the upper-right corner, click **Import entities**.
3. Select **Import discovered entities**.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/gsAeItQRO7Q5luKuFTR1" alt="The &#x27;Import discovered entities&#x27; tile is displayed." width="363"><figcaption></figcaption></figure></div>
4. Select the integration to import from.\
   The **Select entities to import** page is displayed.
5. A list of entities from the integration are displayed. Select the checkboxes next to the entities you want to import. Use the search bar to find entities by name, or click the **Filter icon** in the upper-right corner of the results list to filter by entity type. For Azure DevOps integrations, you can also filter by project name. Search and filters run server-side, so they stay responsive even with large catalogs.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/7JhDfxcU1sxtpRo0UUNf" alt="" width="330"><figcaption></figcaption></figure></div>
6. In the bottom-right corner, click **Next step**.\
   The **Edit details** page is displayed.
7. Configure the following options. The options shown are filtered at runtime based on the `entityType` (e.g. 'Members' is team-only, 'Dependencies' excludes domains/teams) and whether the required integrations are enabled (e.g. 'Communications' requires Slack, 'On-call' requires Opsgenie/PagerDuty, etc.).
   1. From the **Type** drop-down menu, select **Domain.**
   2. In the **Details** sectio&#x6E;**:**
      1. Under **Entity name**, enter a name for the entity (required).
      2. The **Cortex tag** field is auto-populated based on the name of the entity (required). It's a unique identifier for the entity. This is also known as the `x-cortex-tag`.
      3. Under **Description**, enter a description of the entity to help others understand its purpose.
      4. From the **Groups** drop-down men&#x75;**,** select a group or groups [to segment the entity](/ingesting-data-into-cortex/entities-overview/entities/groups).
   3. In the **Repository** section:
      1. From the **Provider** drop-down menu, select the repo provider.
      2. From the **Alias** drop-down menu, select the alias of the connected provider account that has access to the repository.
      3. From the **Repository** drop-down menu, select the repo associated with the entity. If you don't see it listed, click **Refresh repositories** to pull in the latest list.
      4. Under **Basepath**, enter the subdirectory within the repo where the entity's code lives. Leave blank if the entity occupies the entire repo.
   4. In the **Owners** section, define [ownership](/ingesting-data-into-cortex/entities-overview/entities/ownership) for the entity. Ownership can be assigned to either teams or individual users. It's recommended to select team owners to keep the ownership information up to date through any future personnel changes. To add a team or teams, click **Add** in the **Teams** area. To add an individual user or users, click **Add** in the **Users** area.
      * Cortex may recommend owners [based on repository activity](/ingesting-data-into-cortex/entities-overview/entities/ownership#recommendation). You can accept or reject the recommendations.
      * When adding an owner, you can also configure one of the following inheritance options:
        * **Append** - Select this option to add your entity as an additional owner to all of its child entities.
        * **Fallback** - Select this option to add your entity as an owner to child entities if the child entity has no other valid owners.
        * **None** - Select this option if you do not want to configure inheritance. The owner owns the domain you are creating, but will not be configured as an appended or a fallback owner.
   5. In the **Links** section, click **Add** to add links to external documentation, such as runbooks, docs, logs, or custom categories.
   6. In the **Slack channels** section, click **Add** to link a Slack channel to the entity. If enabled, you'll receive notifications about the entity in the selected Slack channel.
   7. In the **Parents** section, select a parent domain or domains from the drop-down menu. This is where you configure the hierarchy for your entity, which can be visualized in the [relationship graph](/ingesting-data-into-cortex/entities-overview/entities/relationship-graph).
   8. In the **Children** section, select children entities. This is where you configure the hierarchy for your entity, which can be visualized in the [relationship graph](/ingesting-data-into-cortex/entities-overview/entities/relationship-graph).
8. If you selected more than one entity, click **Next entity** in the bottom-right corner of the page.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/wOtKl6Ln2jGVBCWTQiWh" alt="The &#x27;Next entity&#x27; link in the bottom-right corner of the page." width="375"><figcaption></figcaption></figure></div>
9. Click **Confirm import**.\
   The entity is imported into Cortex.

### Manually adding domains

1. From the main sidebar, expand **Catalogs**, then select **All entities**.
2. In the upper-right corner, click **Import entities**.
3. Select **Create entities manually**.\
   The **Edit details** page is displayed.
4. Configure the following options. The options shown are filtered at runtime based on the `entityType` (e.g. 'Members' is team-only, 'Dependencies' excludes domains/teams) and whether the required integrations are enabled (e.g. 'Communications' requires Slack, 'On-call' requires Opsgenie/PagerDuty, etc.).
   1. From the **Type** drop-down menu, select **Domain.**
   2. **In the Details section:**
      1. Below **Entity name**, enter a name for the entity (required).
      2. The **Cortex tag** field is auto-populated based on the name of the entity (required). Its a unique identifier for the entity. This is also known as the `x-cortex-tag`.
      3. Below **Description**, enter a description of the entity to help others understand its purpose.
      4. From the **Groups** drop-down men&#x75;**,** select a group or groups [to segment the entity](/ingesting-data-into-cortex/entities-overview/entities/groups).
   3. In the **Repository** section:
      1. From the **Provider** drop-down menu, select the repo provider.
      2. From the **Alias** drop-down menu, select the alias of the connected provider account that has access to the repository.
      3. From the **Repository** drop-down menu, select the repo associated with the entity. If you don't see it listed, click **Refresh repositories** to pull in the latest list.
      4. Below **Basepath**, enter the subdirectory within the repo where the entity's code lives. Leave blank if the entity occupies the entire repo.
   4. In the **Owners** section, define [ownership](/ingesting-data-into-cortex/entities-overview/entities/ownership) for the entity. Ownership can be assigned to either teams or individual users. It's recommended to select team owners to keep the ownership information up to date through any future personnel changes. To add a team or teams, click **Add** in the **Teams** area. To add an individual user or users, click **Add** in the **Users** area.
      * Cortex may recommend owners [based on repository activity](/ingesting-data-into-cortex/entities-overview/entities/ownership#recommendation). You can accept or reject the recommendations.
      * When adding an owner, you can also configure one of the following inheritance options:
        * **Append** - Select this option to add your entity as an additional owner to all of its child entities.
        * **Fallback** - Select this option to add your entity as an owner to child entities if the child entity has no other valid owners.
        * **None** - Select this option if you do not want to configure inheritance. The owner owns the domain you are creating, but will not be configured as an appended or a fallback owner.
   5. In the **Links** section, click **Add** to add links to external documentation, such as runbooks, docs, logs, or custom categories.
   6. In the **Slack channels** section, click **Add** to link a Slack channel to the entity. If enabled, you'll receive notifications about the entity in the selected Slack channel.
   7. In the **Parents** section, select a parent domain or domains from the drop-down menu. This is where you configure the hierarchy for your entity, which can be visualized in the [relationship graph](/ingesting-data-into-cortex/entities-overview/entities/relationship-graph).
   8. In the **Children** section, select children entities. This is where you configure the hierarchy for your entity, which can be visualized in the [relationship graph](/ingesting-data-into-cortex/entities-overview/entities/relationship-graph).
5. Optionally, if you'd like to add another entity, click **Add entity** in the upper-right corner of the page.
6. Click **Confirm import**.\
   The entity is imported into Cortex. If there are any errors, a banner appears at the bottom of the page with the errors that need to be fixed.

### Adding a domain in YAML via GitOps

Before creating a domain entity via GitOps, be sure UI-based editing is disabled in Cortex. See [Managing entities via GitOps](/ingesting-data-into-cortex/entities-overview/entities#managing-entities-via-gitops).

The hierarchy of entities in Cortex is based on that hierarchy being defined in the entity's YAML file; Cortex does not set hierarchies based on a YAML file's location in your repository.

**Domain entity descriptor**

If your entity is a domain, you must specify `x-cortex-type` as `domain`:

```yaml
openapi: 3.0.1
info:
  title: Payments
  description: Domain encompassing all payment processing, billing, and financial transaction services. Owned by the Platform Engineering team.
  x-cortex-tag: payments-domain
  x-cortex-type: domain
```

**Domain hierarchies**

Hierarchies can be defined in two directions:

* **Top-down** (from the parent) - Use the `x-cortex-children` tag in the parent entity YAML to list its children.
* **Bottom-up** (from the child) - Use the `x-cortex-parents` tag in the child entity YAML to list its parents.

Both approaches produce the same hierarchy; choose whichever fits your workflow. For example, if you frequently update a group of child domains together, defining them on the parent YAML is often more efficient.

**Domain parents**

Define another entity as the parent for a domain, allowing you to represent a hierarchy of how your entities are modeled across your workspace using the `x-cortex-parents` tag:

```yaml
openapi: 3.0.1
info:
  title: Payments
  description: Domain encompassing all payment processing, billing, and financial transaction services. Owned by the Platform Engineering team.
  x-cortex-tag: payments-domain
  x-cortex-parents:
    - tag: engineering-domain
    - tag: fintech-domain
```

{% hint style="info" %}
Parent entities must be of type `domain`.
{% endhint %}

**Domain children**

Define a list of other entities as children for a domain, allowing you to represent a hierarchy of how your entities are modeled across your workspace using the `x-cortex-children` tag:

```yaml
openapi: 3.0.1
info:
  title: Payments
  description: Domain encompassing all payment processing, billing, and financial transaction services. Owned by the Platform Engineering team.
  x-cortex-tag: payments-domain
  x-cortex-type: domain
  x-cortex-children:
    - tag: payments-api
    - tag: billing-service
    - tag: payments-database
```

**Ownership inheritance**

A common use case for domains is defining ownership for the subtree of entities. Instead of defining ownership individually for every entity in your catalog, you can define ownership at the domain level and have that pass down to all of its children:

```yaml
openapi: 3.0.1
info:
  title: Payments
  description: Domain encompassing all payment processing, billing, and financial transaction services. Owned by the Platform Engineering team.
  x-cortex-tag: payments-domain
  x-cortex-type: domain
  x-cortex-owners:
    - type: GROUP
      name: cortexapps/payments-platform
      provider: GITHUB
      inheritance: APPEND
```

The `inheritance` type for each owner can be one of `APPEND`, `FALLBACK`, or `NONE`. If not set, inheritance is defaulted to `NONE`.

* `APPEND` - This owner is appended to the list of owners for all child entities.
* `FALLBACK` - In the case where a child has no valid owners, including fallbacks, this fallback will be assigned as the owner. Note that this only applies to a child entity down the hierarchy; it is not the fallback for the parent domain itself.
* `NONE` - This owner owns the domain, but not necessarily any of its children (no inheritance).

**Example cortex.yaml file**

{% hint style="info" %}
The YAML definition for a domain entity can take file names other than `cortex.yaml` or `cortex.yml`; see the [GitOps example repository structure](/configure/gitops#how-gitops-works-in-cortex).
{% endhint %}

```yaml
openapi: 3.0.1
info:
  title: Chat
  description: This is the description of the chat domain.
  x-cortex-tag: chat-domain
  x-cortex-type: domain
  x-cortex-children: # children can be of type service, resource, or domain
    - tag: chat-service
    - tag: chat-database
  x-cortex-parents: # parents can be of type domain only
    - tag: payments-domain
    - tag: web-domain
  x-cortex-owners:
    - type: group
      name: Support
      provider: OKTA
      description: Support Team
  x-cortex-slack:
    channels:
    - name: support-team
      notificationsEnabled: true
      description: This is the description for the support-team Slack channel # optional
  x-cortex-oncall:
    pagerduty:
      id: ASDF2345
      type: SCHEDULE
  x-cortex-apm:
    datadog:
      monitors:
        - 23456
```

### Adding a domain via the Cortex API

You can create, update, and delete domains using the Cortex API. See [Catalog entities](/api/readme/catalog-entities) for more information.

## Viewing domains

The **Domains catalog** page lists every domain entity that's been imported into Cortex. To open it, expand **Catalogs** in the main sidebar and select **Domains**. Each row shows the entity's name and tag.

<div data-with-frame="true"><figure><img src="/files/L2vBSwOOkGQp7YjtNxwH" alt="Overview of the Domains page in the Cortex UI."><figcaption></figcaption></figure></div>

{% hint style="info" %}
Select the **All** tab to view all entities. Select the **Mine** tab to view only entities where you are an owner or member. Cortex saves your selection and restores it the next time you open this page.

<img src="/files/XPX1ltM1su6PpTkrfvfN" alt="" data-size="original">
{% endhint %}

### Searching across and filtering domains

<div data-with-frame="true"><figure><img src="/files/ibQWIR5rvufnK7TNAlil" alt="The search and filter options in the upper-right corner of the page."><figcaption></figcaption></figure></div>

There are several ways to search and filter your domains list.

1. From the main sidebar, expand **Catalogs**, then select **Domains.**
2. Do one of the following:
   * Select the **All** tab to search and filter across all of your organization's domains.
   * Select the **Mine** tab to search and filter only the domains you own.
   * Note that Cortex saves your selection and restores it the next time you open this page.
3. Do any or all of the following:
   * To find specific domains, use the search bar in the upper-right corner of the page and type to search. The search bar shows which fields you can search on and which field your query is matching. For more information, see [Using search in Cortex](/configure/settings/search#using-the-catalog-search-bar).
   * Click **Name** to select whether you want to sort by name or identifier, and whether to sort by ascending or descending order.
   * Click **Display** to choose whether to show archived domains, display [domains by hierarchy](#viewing-the-domain-hierarchy), and/or display empty domains.
   * Click **Filter** to narrow down your list by domain, entity type, group, owner, or team.

### Viewing the domain hierarchy

Follow the steps below to display domains in hierarchy.

1. From the main sidebar, expand **Catalogs**, then select **Domains.**
2. Click **Display** at the top of the domains list.
3. Toggle on **Display hierarchy**.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/3ztjPIuyscUmWsHG5V1A" alt="The &#x27;Display hierarchy&#x27; toggle enabled." width="272"><figcaption></figcaption></figure></div>
4. Click **Done**.

{% hint style="info" %}
You can also view the hierarchy for a given domain on its [entity details page](/ingesting-data-into-cortex/entities-overview/entities/details).
{% endhint %}

### Viewing the Relationships page

If the domain has parents or children, those appear on the Relationships page.

<div align="left" data-with-frame="true"><figure><img src="/files/uV86Cy1Auoskg5vsjV0g" alt="Relationships page for the Authentication domain, showing its parent (Identity) above it and two children (OAuth2 identity service and SSO integration) below it in a vertical hierarchy diagram." width="563"><figcaption></figcaption></figure></div>

To access the Relationships page of an entity:

1. From the main sidebar, expand **Catalogs**, then select **Domains.**
2. Click **Display** at the top of the domains list.
3. Select the entity whose relationship graph you want to view.
4. In the entity sidebar, select **Relationships**.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/VvhmEgsdhDGaGGdUXpSj" alt="Relationships page for the Authentication domain, showing its parent (Identity) above it and two children (OAuth2 identity service and SSO integration) below it in a vertical hierarchy diagram." width="375"><figcaption></figcaption></figure></div>
5. Do any of the following:
   1. Click the **Archive icon** to show or hide archived relationships.
   2. Click the **Filter icon** to narrow the scope of the graph.
   3. By default, the domain hierarchy is displayed as a graph. Click the **Table mode** icon to switch to a tabular view.
   4. Click **Configure** in the upper-right corner to configure the relationship type and its associated entities.

See [Relationship graph](/ingesting-data-into-cortex/entities-overview/entities/relationship-graph) for more information.

## Editing a domain entity

Users with the `Edit Catalog` and `Edit Domains` permissions can edit domain entities.

Domain entities can be modified at any time. Follow the steps below to edit a domain entity.

1. Navigate to the entity's page.
2. In the upper-right corner, click **Configure entity**.\
   The entity details page opens.
3. In the upper-right corner, select either **UI editor** or **YAML editor**.
4. Make your changes. Note that the Cortex tag is uneditable.
5. Click **Save changes**.\
   The domain entity is updated.

{% hint style="info" %}
It's possible to change the entity type via the Cortex YAML. See [Changing an entity's type](/ingesting-data-into-cortex/entities-overview/entities#changing-an-entitys-type) for more information.
{% endhint %}


# Adding teams

In Cortex, teams are a default entity type that bridge your organizational structure with your software catalog. Unlike a simple label or tag, a team in Cortex is a rich entity with its own details page, Scorecard performance tracking, on-call information, Slack channels, and dependency graph, making it the central hub for understanding who owns what and how those owners are performing.

Teams also reflect real-world org structure through parent-child hierarchies, so you can model everything from individual squads up to entire departments. Whether you bring teams in from an identity provider like Okta or Workday, define them in YAML via GitOps, or create them manually in the UI, Cortex keeps team membership and ownership in sync so when your org changes, your catalog stays accurate without extra effort.

Teams are also the foundation of ownership in Cortex. Rather than assign an entity to individual team members, you can assign ownership to an entire team. This makes it easy to assign multiple team members to an entity, and it ensures that when a team’s composition changes, ownership is updated accordingly. See [Defining ownership](/ingesting-data-into-cortex/entities-overview/entities/ownership).

## Adding team entities to Cortex

Users with the `Edit Catalog` and `Edit Domains` permissions can add team entities to Cortex.

When configuring an entity, you can't add archived teams as owners or archived entities as dependencies, parents, or children.

Teams can be added manually, imported, defined in YAML via GitOps, or created via the API.

### Importing teams from an integration

If you already have a source of truth for teams and members, integrate your identity provider to import them. Cortex syncs team pages daily, eliminating duplicate updates when membership changes.

{% hint style="warning" %}
You can only import entities from integrations that have already been configured.
{% endhint %}

Teams can be imported from the following integrations:

* [Azure DevOps](/ingesting-data-into-cortex/integrations/azuredevops)
* [BambooHR](/ingesting-data-into-cortex/integrations/bamboohr)
* [Entra ID](/ingesting-data-into-cortex/integrations/entraid)
* [GitHub](/ingesting-data-into-cortex/integrations/github)
* [GitLab](/ingesting-data-into-cortex/integrations/gitlab)
* [Google](/ingesting-data-into-cortex/integrations/google)
* [Okta](/ingesting-data-into-cortex/integrations/okta)
* [OpsGenie](/ingesting-data-into-cortex/integrations/opsgenie)
* [ServiceNow](/ingesting-data-into-cortex/integrations/servicenow)
  * [Configure table mappings](/ingesting-data-into-cortex/integrations/servicenow#step-2-configure-table-mappings) before importing
* [Workday](/ingesting-data-into-cortex/integrations/workday)
  * Optionally, enable [automatic import of discovered teams](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/teams/team-roles#adjusting-team-settings)

**To import teams from an integration**:

1. From the main sidebar, expand **Catalogs**, then select **All entities**.
2. In the upper-right corner, click **Import entities**.
3. Select **Import discovered entities**.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/gsAeItQRO7Q5luKuFTR1" alt="The &#x27;Import discovered entities&#x27; tile is displayed." width="363"><figcaption></figcaption></figure></div>
4. Select the integration to import from.\
   The **Select entities to import** page is displayed.
5. A list of entities from the integration is displayed. Select the checkboxes next to the entities you want to import. Use the search bar to find entities by name, or click the **Filter icon** in the upper-right corner of the results list to filter by entity type. Search and filters run server-side, so they stay responsive even with large catalogs.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/7JhDfxcU1sxtpRo0UUNf" alt="" width="330"><figcaption></figcaption></figure></div>
6. In the bottom-right corner, click **Next step**.\
   The **Edit details** page is displayed.
7. Configure the following options. The options shown are filtered at runtime based on the `entityType` (e.g. 'Members' is team-only, 'Dependencies' excludes domains/teams) and whether the required integrations are enabled (e.g. 'Communications' requires Slack, 'On-call' requires Opsgenie/PagerDuty, etc.).
   1. From the **Type** drop-down menu, select **Team.**
   2. In the **Details** sectio&#x6E;**:**
      1. Under **Entity name**, enter a name for the entity (required).
      2. The **Cortex tag** field is auto-populated based on the name of the entity (required). It's a unique identifier for the entity. This is also known as the `x-cortex-tag`.
      3. Under **Description**, enter a description of the entity to help others understand its purpose.
      4. From the **Groups** drop-down men&#x75;**,** select a group or groups [to segment the entity](/ingesting-data-into-cortex/entities-overview/entities/groups).
   3. In the **Members** section, click **Add member**. In the side panel, do the following:
      1. Select a user from the drop-down menu OR enter their information manually. If entering the information manually:
         1. Under **Name**, enter the user's first and last name.
         2. Under **Email**, enter the user's email address.
         3. Under **Description**, enter any relevant information about the user, e.g. their timezone.
         4. From the **Team role** drop-down menu, select the user's team role.
         5. Optionally, toggle on **Notifications** to turn on notifications for the user. See [Notifications](/configure/settings/notifications) for more information.
         6. Click **Add**.
   4. In the **Links** section, click **Add** to add links to external documentation, such as runbooks, docs, logs, or custom categories.
   5. In the **Slack channels** section, click **Add** to link a Slack channel to the entity. If enabled, you'll receive notifications about the entity in the selected Slack channel.
   6. In the **Parents** section, select a parent team or teams from the drop-down menu. This is where you configure the hierarchy for your entity, which can be visualized in the [relationship graph](/ingesting-data-into-cortex/entities-overview/entities/relationship-graph).
   7. In the **Children** section, select children entities. This is where you configure the hierarchy for your entity, which can be visualized in the [relationship graph](/ingesting-data-into-cortex/entities-overview/entities/relationship-graph).
   8. In the **Jira** section, click **Add** to connect the entity to Jira. In the side panel, do the following:
      1. From the **Jira Service Type** drop-down menu, select the service type:
         1. **Component** - The sub-sections of a project used to group issues.
         2. **Label** - Text-based tags used to categorize and track issues.
         3. **Space** - The area where teams organize, track, and manage their operational work.
      2. From the **Alias** drop-down menu, select the service type's alias.
      3. Depending on the service type you selected, configure the appropriate field:
         1. Select a Jira component from the drop-down menu.
         2. Enter the name of the label.
         3. Select a Jira space from the drop-down menu.
      4. Click **Add**.
   9. In the **Jira JQL Query** section, select an alias from the drop-down menu. Enter a custom JQL query for the entity.
8. If you selected more than one entity, click **Next entity** in the bottom-right corner of the page.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/wOtKl6Ln2jGVBCWTQiWh" alt="The &#x27;Next entity&#x27; link in the bottom-right corner of the page." width="375"><figcaption></figcaption></figure></div>
9. Click **Confirm import**.\
   The entity is imported into Cortex.

### Manually adding teams

If you don't have an identity provider with updated team information, you can create teams manually in Cortex. Teams are essential for effective ownership, so it's recommended to set them up even without a single source of truth.

1. From the main sidebar, expand **Catalogs**, then select **All entities**.
2. In the upper-right corner, click **Import entities**.
3. Select **Create entities manually**.
4. Configure the following options. The options shown are filtered at runtime based on the `entityType` (e.g. 'Members' is team-only, 'Dependencies' excludes domains/teams) and whether the required integrations are enabled (e.g. 'Communications' requires Slack, 'On-call' requires Opsgenie/PagerDuty, etc.).
   1. From the **Type** drop-down menu, select **Team.**
   2. In the **Details** sectio&#x6E;**:**
      1. Under **Entity name**, enter a name for the entity (required).
      2. The **Cortex tag** field is auto-populated based on the name of the entity (required). Its a unique identifier for the entity. This is also known as the `x-cortex-tag`.
      3. Under **Description**, enter a description of the entity to help others understand its purpose.
      4. From the **Groups** drop-down men&#x75;**,** select a group or groups [to segment the entity](/ingesting-data-into-cortex/entities-overview/entities/groups).
   3. In the **Members** section, click **Add member**. In the side panel, do the following:
      1. Select a user from the drop-down menu OR enter their information manually. If entering the information manually:
         1. Under **Name**, enter the user's first and last name.
         2. Under **Email**, enter the user's email address.
         3. Under **Description**, enter any relevant information about the user, e.g. their timezone.
         4. From the **Team role** drop-down menu, select the user's team role.
         5. Optionally, toggle on **Notifications** to turn on notifications for the user. See [Notifications](/configure/settings/notifications) for more information.
         6. Click **Add**.
   4. In the **Links** section, click **Add** to add links to external documentation, such as runbooks, docs, logs, or custom categories.
   5. In the **Slack channels** section, click **Add** to link a Slack channel to the entity. If enabled, you'll receive notifications about the entity in the selected Slack channel.
   6. In the **Parents** section, select a parent team or teams from the drop-down menu. This is where you configure the hierarchy for your entity, which can be visualized in the [relationship graph](/ingesting-data-into-cortex/entities-overview/entities/relationship-graph).
   7. In the **Children** section, select children entities. This is where you configure the hierarchy for your entity, which can be visualized in the [relationship graph](/ingesting-data-into-cortex/entities-overview/entities/relationship-graph).
   8. In the **Jira** section, click **Add** to connect the entity to Jira. In the side panel, do the following:
      1. From the **Jira Service Type** drop-down menu, select the service type:
         1. **Component** - The sub-sections of a project used to group issues.
         2. **Label** - Text-based tags used to categorize and track issues.
         3. **Space** - The area where teams organize, track, and manage their operational work.
      2. From the **Alias** drop-down menu, select the service type's alias.
      3. Depending on the service type you selected, configure the appropriate field:
         1. Select a Jira component from the drop-down menu.
         2. Enter the name of the label.
         3. Select a Jira space from the drop-down menu.
      4. Click **Add**.
   9. In the **Jira JQL Query** section, select an alias from the drop-down menu. Enter a custom JQL query for the entity.
5. If you selected more than one entity, click **Next entity** in the bottom-right corner of the page.
6. Click **Confirm import**.\
   The entity is imported into Cortex.

### Adding a team in YAML via GitOps

Before creating a team entity via GitOps, be sure UI-based editing is disabled in Cortex. See [Managing entities via GitOps](/ingesting-data-into-cortex/entities-overview/entities#managing-entities-via-gitops).

Teams can be created manually in Cortex or defined directly in the entity descriptor, where they can also be assigned as owners. See [Defining ownership](/ingesting-data-into-cortex/entities-overview/entities/ownership) for more information.

If your entity is a team, you must specify `x-cortex-type` as `team` :

```yaml
openapi: 3.0.1
info:
  title: On-Call Illuminati
  description: They know things. Dark things. Usually around 3am on a Friday.
  x-cortex-tag: on-call-illuminati
  x-cortex-type: team
```

{% hint style="info" %}
The `x-cortex-team` tag has two main sections: `groups` and `members`.
{% endhint %}

#### **Adding groups to the team entity descriptor**

Use `groups` to connect a team entity to a matching team on another platform you've integrated with Cortex (such as Okta, GitHub, or Azure AD). Only one group can be linked per team entity.

For example, you can specify:

```yaml
openapi: 3.0.1
info:
  title: Firewall Whisperers
  description: They don't block traffic, they have stern conversations with it.
  x-cortex-type: team
  x-cortex-tag: firewall-whisperers
  x-cortex-team:
      groups:
      - name: okta-firewall-whisperers
        provider: OKTA
```

Specifying `okta-firewall-whisperers` under `groups` populates your team with every member of that Okta group.

Once linked, any entity that lists `okta-firewall-whisperers` in `x-cortex-owners` automatically recognizes `firewall-whisperers` as an owning team, no extra configuration required.

For example, a service owned by the team would look like:

```yaml
openapi: 3.0.1
info:
  title: Perimeter Defense API
  description: Handles ingress rules, packet inspection, and the occasional stern talking-to.
  x-cortex-type: service
  x-cortex-tag: perimeter-defense-api
  x-cortex-owners:
    - type: group
      name: okta-firewall-whisperers
      provider: OKTA
```

#### **Adding team members to the team entity descriptor**

Use `members` when you need to define team membership directly in Cortex, rather than syncing from an external platform. This is useful when a team doesn't map cleanly to a single group in one of your integrations, or when you need finer-grained control over who belongs and in what role.

For example, you can specify:

```yaml
openapi: 3.0.1
info:
  title: Velocity Merchants
  description: They move fast and only sometimes break things. Mostly on Fridays.
  x-cortex-type: team
  x-cortex-tag: velocity-merchants
  x-cortex-team:
      members:
      - name: Sprint Shepherd
        email: sprint.shepherd@cortexlabs.io
        notificationsEnabled: true
        roles: 
          - tag: product-manager
      - name: Merge Maestro
        email: merge.maestro@cortexlabs.io
        notificationsEnabled: true
        roles: 
          - tag: engineering-manager
          - tag: manager 
```

Members support roles, and a single member can hold more than one. When a member's email matches an active Cortex account, that user will see the team appear under their Mine tab in any catalog that includes teams.

The `role` field is optional per member. Roles themselves [must be defined](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/teams/team-roles) in the entity's settings page, under the **Teams** tab.

{% hint style="info" %}
The `role` field in member is optional. In order to be considered valid, a team must have a non-empty group.
{% endhint %}

#### **Team children**

Use `x-cortex-children` to define sub-teams, letting you model your org structure as a hierarchy in Cortex. The full hierarchy is visible in the Teams catalog.

{% hint style="info" %}
Cortex derives hierarchy from what's declared in each YAML file, not from where those files live in your repository.
{% endhint %}

For example, you can specify:

```yaml
openapi: 3.0.1
info:
  title: Platform Overlords
  description: They don't write features. They write the things that let others write features.
  x-cortex-tag: platform-overlords
  x-cortex-type: team
  x-cortex-children:
  - tag: infra-gremlins
  - tag: dev-experience-dreamers
```

#### **Team parents**

`x-cortex-children` defines relationships top-down, but if it's more natural to declare a team's place in the hierarchy from its own YAML, use `x-cortex-parents` instead. Both approaches produce the same result; use whichever fits how your team's YAML is maintained.

For example, you can specify:

```yaml
openapi: 3.0.1
info:
  title: Microservices Anonymous
  description: I'm a checkout-service, and I depend on 47 other services.
  x-cortex-tag: microservices-anonymous
  x-cortex-type: team
  x-cortex-parents:
  - tag: platform-overlords
  - tag: engineering-org
```

#### **Example cortex.yaml**

The example below shows a fully defined team entity combining groups, members, children, Slack, and PagerDuty. Note that the file doesn't need to be named `cortex.yaml` or `cortex.yml` . See [GitOps example repository structure](/configure/gitops#how-gitops-works-in-cortex) for more information.

```yaml
openapi: 3.0.1
info:
  title: Latency Avengers
  description: Milliseconds are their nemesis. They have the dashboards to prove it.
  x-cortex-tag: latency-avengers
  x-cortex-type: team
  x-cortex-team:
      groups:
      - name: okta-latency-avengers
        provider: OKTA
      members:
      - name: P99 Wrangler
        email: p99.wrangler@cortexlabs.io
        notificationsEnabled: true
      - name: Cache Evangelist
        email: cache.evangelist@cortexlabs.io
        notificationsEnabled: true
  x-cortex-children: # children can be of type team
    - tag: frontend-speed-demons
    - tag: cdn-whisperers
  x-cortex-slack:
    channels:
    - name: latency-avengers
      notificationsEnabled: true
      description: For when dashboards go red and everyone's pinging everyone. # optional
  x-cortex-oncall:
    pagerduty:
      id: P99XQRS
      type: SCHEDULE
```

### Adding a team via the Cortex API

You can create, update, and delete teams using the Cortex API. See [Teams](/api/readme/teams) for more information.

## Editing a team entity

Users with the `Edit Catalog` and `Edit Teams` permissions can edit team entities.

Team entities can be modified at any time. Follow the steps below to edit a team entity.

1. Navigate to the entity's page.
2. In the upper-right corner, click **Configure entity**.\
   The entity details page opens.
3. In the upper-right corner, select either **UI editor** or **YAML editor**.
4. Make your changes. Note that the Cortex tag is uneditable.
5. Click **Save changes**.\
   The team entity is updated.

{% hint style="info" %}
It's possible to change the entity type via the Cortex YAML. See [Changing an entity's type](/ingesting-data-into-cortex/entities-overview/entities#changing-an-entitys-type) for more information.
{% endhint %}


# Viewing teams

This article covers viewing teams in Cortex. For information on adding a team to Cortex, see [Adding teams](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/teams). For information on adding users to teams and assigning roles, see [Team roles](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/teams/team-roles). Refer to [Team ownership entity editing](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/teams/team-entity-editing) for information on entity editing.

## Viewing the Teams catalog page

The **Teams** **catalog** page lists every team entity that's been added to Cortex. To open it, expand **Catalogs** in the main sidebar and select **Teams**. Each row shows the entity's name and number of team members.

<div align="left" data-with-frame="true"><figure><img src="/files/Cbf4nBBGapnvvyjCYOJ5" alt="Overview of the Teams page in the Cortex UI." width="563"><figcaption></figcaption></figure></div>

{% hint style="info" %}
Select the **All** tab to view all entities. Select the **Mine** tab to view only entities where you are an owner or member. Cortex saves your selection and restores it the next time you open this page.

<img src="/files/XPX1ltM1su6PpTkrfvfN" alt="" data-size="original">
{% endhint %}

### Searching across and filtering teams

<div align="left" data-with-frame="true"><figure><img src="/files/KlCyLpikBhcmDtt7UKUs" alt="The search and filter options in the upper-right corner of the page."><figcaption></figcaption></figure></div>

There are several ways to search and filter your teams list.

1. From the main sidebar, expand **Catalogs**, then select **Teams.**
2. Do one of the following:
   * Select the **All** tab to search and filter across all of your organization's teams.
   * Select the **Mine** tab to search and filter only the teams you own.
   * Note that Cortex saves your selection and restores it the next time you open this page.
3. Do any or all of the following:
   * To find specific teams, use the search bar in the upper-right corner of the page and type to search. The search bar shows which fields you can search on and which field your query is matching. For more information, see [Using search in Cortex](/configure/settings/search#using-the-catalog-search-bar).
   * Click **Name** to select whether you want to sort by name or identifier, and whether to sort by ascending or descending order.
   * Click **Display** to choose whether to show archived teams and/or display teams by hierarchy.
   * Click **Filter** to narrow down your list by team, member, or group.

### Viewing team hierarchy

Follow the steps below to display teams in hierarchy.

1. From the main sidebar, expand **Catalogs**, then select **Teams.**
2. Click **Display** at the top of the teams list.
3. Toggle on **Display hierarchy**.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/3ztjPIuyscUmWsHG5V1A" alt="The &#x27;Display hierarchy&#x27; toggle enabled." width="272"><figcaption></figcaption></figure></div>
4. Click **Done**.

{% hint style="info" %}
You can also view the hierarchy for a given team on its [entity details page](/ingesting-data-into-cortex/entities-overview/entities/details).
{% endhint %}

#### Understanding hierarchies

Cortex lets you structure teams to reflect your organization's real hierarchy, whether you're creating teams manually or importing them. Any team can be both a parent to other teams and a child of another, so multi-level structures are fully supported.

The Teams catalog page displays individual and parent teams by default. An arrow next to a team's name indicates it has children; click to expand and view child teams.

In the image below, `My Company` is a parent team with 7 child teams nested under it.

<div align="left" data-with-frame="true"><figure><img src="/files/Sq9XBozAHUjNkrVb2TsF" alt="An arrow icon is displayed next to a parent team. Click the arrow to expand the hierarchy."><figcaption></figcaption></figure></div>

### Viewing the Scorecard leaderboard

<div align="left" data-with-frame="true"><figure><img src="/files/jc4Sw9qensutrkbW4ptn" alt="The Scorecard leaderboard is displayed on the Teams page." width="563"><figcaption></figcaption></figure></div>

On the right side of the Teams catalog page is the Scorecard leaderboard, which highlights the 10 best-performing teams within your organization.

The leaderboard is calculated from the average of [Scorecard](/standardize/scorecards) scores for all entities owned by a team. Change in rank is based on the team's score 7 days ago. You can use the drop-down to select a different Scorecard, allowing you to view the leaderboard based on specific Scorecards.

{% hint style="success" %}
The leaderboard gamifies entity quality and encourages team members to achieve goals. This creates a culture of accountability, where everyone has visibility into how they're performing.
{% endhint %}

## Viewing an individual team's page

Every team has a dedicated details page displaying its key information. Follow the steps below to access a team's details page.

1. From the main sidebar, expand **Catalogs**, then select **Teams.**
2. Select a team to view its individual page.

On the team's details page, you’ll find the following:

* The [entity details sidebar](/ingesting-data-into-cortex/entities-overview/entities/details#configuring-the-entity-details-sidebar)<br>

  <div align="left" data-with-frame="true"><figure><img src="/files/PLfwRNs7runLfnip30IC" alt="The entity details sidebar." width="375"><figcaption></figcaption></figure></div>
* The [team name and tag](/ingesting-data-into-cortex/entities-overview/entities/details#locating-an-entitys-unique-identifiers)
* The main **Overflow menu** icon and the **Configure entity** button
* The **Overview** tab:
  * The **Team members** section
    * Includes a list of all team members, their roles, and their emails. When available, Cortex pulls in profile photos from your Git provider.
  * The **Scorecards** section
    * An overview of how the team is performing across Scorecards. By default, the snapshot shows the level that the team’s entities have reached in each Scorecard. Optionally, click the arrow next to This entity only to include entity's children.
  * The **Latest events** section
    * A list of recent events associated with this team, such as alerts from [PagerDuty](/ingesting-data-into-cortex/integrations/pagerduty).
* The **Entities** tab:
  * Shows a list of linked entities, including number of incidents and health status. Click into an entity to learn more about it. Optionally, click the **Overflow menu** to copy the entity to your clipboard or view the entity in the relationship graph.
* The [metadata sidebar](/ingesting-data-into-cortex/entities-overview/entities/details#configuring-the-entity-metadata-sidebar)


# Team roles

Assigning roles to your team members in Cortex helps you control what each individual can see and do within your organization. This article walks you through how to add roles and assign them to team members. For information on adding a team to Cortex, see [Adding teams](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/teams). See [Viewing teams](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/teams/viewing-teams) for information about viewing teams. Refer to [Team ownership entity editing](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/teams/team-entity-editing) for information on entity editing.

## Adding a user to a team

Refer to Step 4c in [Manually adding teams](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/teams#manually-adding-teams).

A few things to keep in mind:

* Users can only be added to manually created teams, and roles can only be assigned to manually created members.
* Members imported from an identity integration keep their imported role. To change it, update the role in the integration. The change then syncs to Cortex.

## Adding team member roles

Cortex allows you to define roles that can be assigned to team members. Follow the steps below to create a new team member role.

1. From the main sidebar, click your avatar in the bottom-left corner.
2. Click **Settings**.
3. From the **Settings** menu, locate the **Workspace** section, then expand **Entities**.
4. Select **Teams**.
5. In the **Roles** section, click **Add role**.
6. In the right pane, configure the role:
   * Under **Role name**, enter the name of the role.
   * Under **Tag**, the tag auto-populates based on the role name.
   * Under **Description**, enter a description of the role.
   * By default, **Enable notifications by default** is toggle on. If enabled, members with this role receive relevant updates on Scorecards, Initiatives, and more.<br>

     <div align="left" data-with-frame="true"><figure><img src="/files/Xcor2LDNpetLnCW2fAtK" alt="The &#x27;Add role&#x27; pane." width="375"><figcaption></figcaption></figure></div>
7. Click **Add role**.\
   The role is added to your workspace.

### Applying a role to a team member OR editing a team member's role

Roles can only be applied to manually created team members. Members imported from an identity integration retain the role assigned during import.

1. From the main sidebar, expand **Catalogs**, then select **Teams**.
2. Do one of the following:
   * Select the **All** tab to search and filter across all of your organization's entities.
   * Select the **Mine** tab to search and filter only the entities you own.
   * Note that Cortex saves your selection and restores it the next time you open this page.
3. Select a team.
4. In the upper-right corner, click **Configure entity**.
5. From the configuration sidebar, select **Members**.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/GDvTnxTmmRi7XlyRHC72" alt="The &#x27;Members&#x27; tab in the configuration sidebar." width="375"><figcaption></figcaption></figure></div>
6. Locate the team member, then click the **edit icon** next to their name.
7. In the side panel, select a role from the **Team role** drop-down menu.
8. Click **Update**.

## Removing a team member

You can remove a team member from a manually added team at any time.

Members imported from an identity integration keep their imported role. To remove them from a team, you'll need to remove them in the integration. The change then syncs to Cortex.

1. From the main sidebar, expand **Catalogs**, then select **Teams**.
2. Do one of the following:
   * Select the **All** tab to search and filter across all of your organization's entities.
   * Select the **Mine** tab to search and filter only the entities you own.
   * Note that Cortex saves your selection and restores it the next time you open this page.
3. Select a team.
4. In the upper-right corner, click **Configure entity**.
5. From the configuration sidebar, select **Members**.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/GDvTnxTmmRi7XlyRHC72" alt="The &#x27;Members&#x27; tab in the configuration sidebar." width="375"><figcaption></figcaption></figure></div>
6. Locate the team member, then click the **trash icon** next to their name.\
   The **Remove team member** window opens.
7. Click **Delete**.\
   The team member is removed from the team.

## Adjusting team settings

Users with the `Configure Settings` permission can adjust system-wide settings for entities.

**To access team entity settings**:

1. From the main sidebar, click your avatar in the bottom-left corner.
2. Click **Settings**.
3. From the **Settings** menu, locate the **Workspace** section, then expand **Entities**.
4. Select **Teams**.
5. From the **Team settings** tab do any of the following:
   1. In the **Team settings** section, toggle on or off the following:
      1. **Auto import Workday teams** - If enabled, Cortex automatically imports any discovered teams and team relationships from Workday. See [the Workday documentation](/ingesting-data-into-cortex/integrations/workday/using-the-integration-for-workday#automatically-import-teams) for more information.
      2. **Team ownership entity editing** - If enabled, only specific members of the team can edit the entity. See [Team ownership entity editing](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/teams/team-entity-editing) for more information.
      3. **Give access to all team members** - If enabled, all team members are granted edit access to the entities owned by the team. Note that turning off editing access for specific members is not supported.
      4. **Sync team roles from identity providers** - If enabled, Cortex automatically assigns roles to team members based on your enabled identity providers. Select the **Identity providers** tab to view your enabled identity providers.
   2. In the **Roles** section, add, edit, or remove team member roles.
6. From the **Identity providers** tab, enable Cortex to use identity providers to sync teams and team memberships. Toggle on an identity provider to enable automatic sync.
   * When you import teams, Cortex shows the enabled IdPs listed on this page as import options.


# Team ownership entity editing

Organizations can restrict entity editing to the teams and members who own each entity, avoiding the need to grant edit permissions across the entire workspace. Ownership must be defined on an entity for this to apply.

You can also grant all team members edit access by default.

This article walks you through how to enable the team ownership entity editing feature. For information on adding a team to Cortex, see [Adding teams](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/teams). See [Viewing teams](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/teams/viewing-teams) for information about viewing teams. Refer to [Team roles](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/teams/team-roles) for information on how to add roles and assign them to team members.

## Step 1: Enabling team ownership entity editing

Users with the `Configure Settings` permission can enable the team ownership entity editing setting.

Team ownership entity editing must be enabled before you can assign entity editing access.

{% hint style="warning" %}
The `Configure Catalogs` permission supersedes **Team ownership entity editing**.
{% endhint %}

1. From the main sidebar, click your avatar in the bottom-left corner.
2. Click **Settings**.
3. From the **Settings** menu, locate the **Workspace** section, then expand **Entities**.
4. Select **Teams**.
5. In the **Team settings** section, toggle on **Team ownership entity editing**. Enabling this feature ensures that the [default user role](/configure/settings/managing-users/permissioning#default-roles) is automatically updated and will not include generic permissions for editing entities.
   * Note that the `Configure Catalogs` [permission](/configure/settings/managing-users/permissioning) supersedes the **Team ownership entity editing** feature, so any users assigned a custom role with that permission can continue editing all entities, regardless of ownership. Remove the `Configure Catalogs` permission from the custom role(s) to restrict the ability to edit entities.
6. Optionally, toggle on **Give edit access to all team members** to give editing access to all members of the team who own an entity.

## Step 2: Specifying team editors

Follow the steps below to define editing access to specific users within a team. Note that you cannot specify specific users if the **Give access to all team members** option is enabled. See [Adjusting team settings](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/teams/team-roles#adjusting-team-settings) for more information.

1. From the main sidebar, expand **Catalogs**, then select **Teams**.
2. Do one of the following:
   * Select the **All** tab to search and filter across all of your organization's entities.
   * Select the **Mine** tab to search and filter only the entities you own.
   * Note that Cortex saves your selection and restores it the next time you open this page.
3. Select a team.
4. In the upper-right corner, click **Configure entity**.
5. From the configuration sidebar, select **Members**.
6. Locate the user you want to make an editor, then click the **pencil icon** next to their name.
7. In the side panel, toggle on the **Editor** setting. Note that if the team member does not have an associated Cortex account, they **cannot** be made an editor.
8. Click **Update**.

On the team page in Cortex, the **Team members** tab displays an `Editor` label next to any members you've marked as editors. Members without a configured [identity mapping](/configure/settings/managing-users/identity-mapping) won't appear as editors.

<div align="left" data-with-frame="true"><figure><img src="/files/denM4ftYGzrCdpSCmpK6" alt="The &#x27;Editor&#x27; label next to a team member&#x27;s name on the team page."><figcaption></figcaption></figure></div>

## Troubleshooting and FAQ

See frequently asked questions below.

**Can team editors import entities?**

No, team editors can not import entities. To import entities, a user must have the `Configure Catalog` permission, which also gives users the permission to edit ALL entities, not just the ones they own.

**Can team editors delete entities they own?**

No, team editors can not delete any entities, even if they own them.

**Can users with the Viewer role edit entities if this feature is enabled?**

Yes, if they are a member of the owning team and either Give edit access to all team members is enabled or they have been individually marked as an editor. The team ownership editing feature overrides workspace-level role restrictions for editing team-owned entities.

**Why does a team member not have the** `Editor` **label after I enabled edit access to all team members?**

This can happen if the team member's [identity mapping](/configure/settings/managing-users/identity-mapping) has not been configured.


# Adding custom entity types

Cortex ships with built-in entity types—services, domains, and teams—to cover common engineering assets, but an organization's catalog rarely stops there. Custom entity types let you model anything your teams track, such as employees, vendors, data pipelines, and compliance controls, with structured metadata you define and enforce.

## Prerequisites

Creating a custom entity type is a two-step process:

1. First, define the ***entity type*** itself (its name, icon, and JSON schema)
   * Users or API keys must have the `Edit Entity Types` permission
2. Next, [create individual entities](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/entity-types/creating-custom-entities) of that type via the UI, GitOps, or API.
   * Users or API keys must have the `Edit Entities` permission

## Creating a custom entity type

Users or API keys with the `Edit Entity Types` permission can create, edit, and delete entity types.

Custom entity types can be created manually in the Cortex UI or via the API. The type you define— its schema, required fields, and metadata—shape how entities of that type are imported and validated going forward. Once the type exists, you can create entities of that type through the UI, API, or GitOps.

When configuring an entity, you can't add archived teams as owners or archived entities as dependencies, parents, or children.

### Creating a custom entity type manually in the Cortex UI

1. From the main sidebar, expand **All Catalogs**, then select **All entities**.
2. Select the **Entity types** tab.
3. In the upper-right corner, click **Create**, then select **Create new entity type**.\
   The **Create entity type** page opens.
4. In the **Details** section, do the following:
   1. Under **Entity type name**, enter a human-readable name that will appear in the catalog for this entity type (required).
   2. Under **Identifier**, enter a unique identifier consisting of letters, digits, and hyphens that corresponds to the entity type (required). This is used to specify the type defined in the YAML definitions for imported entities.
   3. Under **Description**, enter a description for the entity type.
   4. Under **Display icon**, click **Edit** to select an icon to appear alongside the entity type throughout Cortex.
5. In the **Schema** section, do the following:
   1. Define a [JSON schema](#json-schema-for-custom-entity-types) to be used to validate the `x-cortex-validation` block of a given entity’s YAML.
      * This can be used to enforce certain attributes about entities, such as a region or version number. Attributes defined in the schema will be required when creating an entity of that type, which can then be validated in Scorecards.
      * In the example screenshot below, the custom entity type `Employee` represents individuals in an organization. The schema requires each entity to include a `location` , so every entity of type "Employee" must define the employee's location.<br>

        <div align="left" data-with-frame="true"><figure><img src="/files/3eUUZpoQ0Wayfsaq8uwY" alt="A custom entity called &#x22;Employee&#x22; contains example JSON, demonstrating how to configure a required &#x22;location&#x22; field." width="339"><figcaption></figcaption></figure></div>
6. Click **Create**.\
   The new entity type now appears in the **Entity types** tab. You can now import entities of the same type into Cortex.

To automatically assign entities of this type to a specific catalog, configure the catalog's entity types when [creating a new catalog](/ingesting-data-into-cortex/catalogs#create-custom-catalogs). Alternatively, [edit an existing catalog](/ingesting-data-into-cortex/catalogs#edit-catalogs) to add the type.

### Creating a custom entity type via the API

You can create, update, and delete entity types using the [Cortex API](/api/readme/catalog-entities). Learn more about the [JSON schema](#json-schema-for-custom-entity-types).

## JSON schema for custom entity types

Entity type definitions require a JSON schema that outlines the attributes that entities should conform to.

Custom entity type definitions are powered by the open-source [JSON Schema](https://json-schema.org/) project.

The JSON schema for a custom entity type ensures consistency and validation when creating entities of that type. The attributes listed under `required` in the schema must be defined for entities of that type according to the outlined `properties`.

In the example below, `location` is required when creating this type of entity, but the schema also includes `department` as a possible property.

```json
{
  "type": "object",
  "required": [
    "location"
  ],
  "properties": {
    "location": {
      "type": "string"
    },
    "department": {
      "type": "string"
    }
  }
}
```

<table><thead><tr><th width="130.2265625">Field</th><th width="462.5546875">Definition</th><th align="center">Required?</th></tr></thead><tbody><tr><td><code>type</code></td><td>Type of entity and/or required component: <code>array</code>, <code>boolean</code>, <code>integer</code>, <code>null</code>, <code>number</code>, <code>object</code>, or <code>string</code></td><td align="center"><i class="fa-check">:check:</i></td></tr><tr><td><code>required</code></td><td>Required specs for the entity type</td><td align="center"><i class="fa-x">:x:</i></td></tr><tr><td><code>properties</code></td><td>Properties of the required specs (including <code>type</code>). Required when <code>required</code> is non-empty.</td><td align="center">Conditional</td></tr></tbody></table>

### Adding an entity schema for new custom entities

When creating a new entity of the custom type, if the entity type's JSON schema requires certain attributes, you must include the metadata for those attributes on that entity.

<details>

<summary>Adding attributes via JSON schema</summary>

When creating a custom entity in the Cortex UI, enter the entity's attribute values as JSON in the **Schema** field.

Using the [example above](#json-schema-for-custom-entity-types), the schema format looks like:

```json
{
    "location": "San Diego",
    "department": "Engineering"
}
```

</details>

<details>

<summary>Adding attributes via YAML</summary>

For GitOps workflows or direct YAML editing in the Cortex UI, define the custom entity's metadata in the YAML.

Using the [example above](#json-schema-for-custom-entity-types), the entity YAML looks like:

```
x-cortex-type: org-employees
x-cortex-definition:
   location: San Diego
   department: Engineering
```

The `x-cortex-type` (the custom entity type) and the `x-cortex-definition` are required when creating a custom entity. Learn more under [Create custom entities in the entity descriptor](#entity-descriptor).

</details>

## Metadata in the entity details page

Defining a JSON schema enables visibility on an [entity's details page](/ingesting-data-into-cortex/entities-overview/entities/details). The schema and the defined properties appear under the **Overview** section on the entity's overview, making it easy for you to identify key specs.

In the example below, the entity "Alabama" displays metadata for the property `location` :

<div align="left" data-with-frame="true"><figure><img src="/files/ThgCpbokTcdfjFzRe1vR" alt="The entity, &#x22;Alabama&#x22;, displays metadata for the property &#x27;location&#x27;." width="563"><figcaption></figcaption></figure></div>

To access an entity's details page, expand **All Catalogs** from the main sidebar, then select **All entities**. Select an entity to view its details.


# Creating custom entities

This article explains how to create a custom entity. For information on creating a custom entity *type*, see [Adding custom entity types](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/entity-types).

## Prerequisites

1. Users or API keys with the `Edit Entities` permission can create custom entities.
2. A [custom entity type](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/entity-types#creating-a-custom-entity-type). Once the custom entity type is created, you can begin creating entities of that type.

## Creating a custom entity

After creating the custom entity type, you can create entities of that custom type in the Cortex UI, in the entity descriptor YAML via GitOps, or via the Cortex API.

### Creating a custom entity manually in the Cortex UI

1. From the main sidebar, expand **Catalogs**, then select **All entities**.
2. In the upper-right corner, click **Import entities**.
3. Select **Create entities manually**.\
   The **Edit details** page opens.
4. Configure the following options. The options shown are filtered at runtime based on the `entityType` (e.g. 'Members' is team-only, 'Dependencies' excludes domains/teams) and whether the required integrations are enabled (e.g. 'Communications' requires Slack, 'On-call' requires Opsgenie/PagerDuty, etc.).
   1. In the **Type** section:
      1. From the drop-down menu, select your custom entity type (required).
      2. Below **Entity schema**, enter a JSON schema to define your custom entity. For example, if the entity type's schema requires `location` and `department`, your new entity's schema might look like:

         <div align="left" data-with-frame="true"><figure><img src="/files/IwEbFOTmGnsmflzz3iuy" alt="The entity schema includes &#x22;location&#x22; and &#x22;department&#x22; metadata." width="343"><figcaption></figcaption></figure></div>

         * Optionally, click **Show example** above the schema to view an example of how the entity's schema should be formatted. The **Entity Schema Example** window opens. To use the example as a starting point, click **Copy example**, then paste it into the **Entity schema** text editor. See [JSON schema for custom entity types](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/entity-types#json-schema-for-custom-entity-types) for more information.
   2. In the **Details** section:
      1. Under **Entity name**, enter a name for the entity (required).
      2. The **Cortex tag** field is auto-populated based on the name of the entity (required). It's a unique identifier for the entity. This is also known as the `x-cortex-tag`.
      3. Under **Description**, enter a description of the entity to help others understand its purpose.
      4. From the **Groups** drop-down men&#x75;**,** select a group or groups [to segment the entity](/ingesting-data-into-cortex/entities-overview/entities/groups).
   3. In the **Repository** section:
      1. From the **Provider** drop-down menu, select the repo provider.
      2. From the **Alias** drop-down menu, select the alias of the connected provider account that has access to the repository.
      3. From the **Repository** drop-down menu, select the repo associated with the entity. If you don't see it listed, click **Refresh repositories** to pull in the latest list.
      4. Below **Basepath**, enter the subdirectory within the repo where the entity's code lives. Leave blank if the entity occupies the entire repo.
   4. In the **Owners** section, define [ownership](/ingesting-data-into-cortex/entities-overview/entities/ownership) for the entity. Ownership can be assigned to either teams or individual users. It's recommended to select team owners to keep the ownership information up to date through any future personnel changes. To add a team or teams, click **Add** in the **Teams** area. To add an individual user or users, click **Add** in the **Users** area.
      * Cortex may recommend owners [based on repository activity](/ingesting-data-into-cortex/entities-overview/entities/ownership#recommendation). You can accept or reject the recommendations.
   5. In the **Links** section, click **Add** to add links to external documentation, such as runbooks, docs, logs, or custom categories.
   6. In the **Slack channels** section, click **Add** to link a Slack channel to the entity. If enabled, you'll receive notifications about the entity in the selected Slack channel.
   7. In the **Parents** section, select a parent domain or domains from the drop-down menu. This is where you configure the hierarchy for your entity, which can be visualized in the [relationship graph](/ingesting-data-into-cortex/entities-overview/entities/relationship-graph).
   8. In the **Dependencies** section, click **Add entity** to select an entity or entities that this entity depends on. These can be visualized in the [relationship graph](/ingesting-data-into-cortex/entities-overview/entities/relationship-graph).
5. If you selected more than one entity, click **Next entity** in the bottom-right corner of the page.
6. Click **Confirm import**.\
   The entity is imported into Cortex.

### Adding a custom entity in YAML via GitOps

Before creating a custom entity via GitOps, be sure UI-based editing is disabled in Cortex. See [Managing entities via GitOps](/ingesting-data-into-cortex/entities-overview/entities#managing-entities-via-gitops).

Custom entity types require both `x-cortex-type` and `x-cortex-definition`.

The `x-cortex-definition` field is validated against the entity type definition created via the UI or API. Even if your custom entity type has no specific requirements, you must still provide a non-null definition, e.g. `x-cortex-definition: {}`.

**Example cortex.yaml**

```yaml
openapi: 3.0.1
info:
  title: Henry Tallman
  description: Product Manager
  x-cortex-tag: employee-henry
  x-cortex-type: org-employees
  x-cortex-definition:
    location: Cleveland
    department: Product
```

### Creating a custom entity via the API

You can create, read, update, and delete entities via the [Cortex API](/api/readme/catalog-entities).

{% hint style="info" %}
Users or API keys must have the `Delete Entities` permission to delete entities.
{% endhint %}


# Managing custom entities

This article explains how to manage custom entities. For information on managing custom entity *types*, [refer to the documentation](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/entity-types/managing-custom-entity-types).

## Adding custom entities to catalogs

When you import or create an entity, Cortex automatically assigns it to a catalog based on that catalog's entity type criteria. When you create a [custom catalog](/ingesting-data-into-cortex/catalogs), you define this criteria.

By default, any custom entity types you create belong to the Infrastructure catalog. To assign a custom entity type to a different catalog, add it to that catalog's definition.

## Editing a custom entity

Users or API keys with the `Edit Entities` permission can edit a custom entity.

Follow the steps below to edit a custom entity.

1. Navigate to the [entity's details page](/ingesting-data-into-cortex/entities-overview/entities/details).
2. In the upper-right corner, click **Configure entity**.
3. Make any necessary changes. Note that the **Type** and **Cortex tag** fields are uneditable.
   * The left sidebar provides additional editing options.
4. Click **Save changes**.


# Managing custom entity types

This article explains how to manage custom entity *types*. For information on managing custom entities, [refer to the documentation](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/entity-types/managing-custom-entities).

## Viewing custom entity types

After [creating a custom entity type](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/entity-types), you can view or edit its schema, view a list of entities of the same type, and validate the schema of entities of that type.

1. From the main sidebar, expand **Catalogs**, then select **All entities**.
2. Select the **Entity types** tab.
3. Select an entity type.\
   A list of associated entities is displayed.
4. Do any or all of the following:
   * Select an entity to view more information about it. Learn more about the health and incident columns in Step 3 of [Searching across and filtering entities](/ingesting-data-into-cortex/entities-overview/entities#searching-across-and-filtering-entities).
   * Select the **Schema** tab to copy the schema to your clipboard.
   * Select the **Schema linter** tab to validate the schema for a custom entity type. See [Validating an entity schema for a custom entity type](#validating-an-entity-schema-for-a-custom-entity-type) for more information.
   * Click **Edit** in the upper-right corner to edit the entity type's information and schema. Note that the **Identifier** field is uneditable.
   * Click the **Overflow menu** to delete the entity type.

{% hint style="info" %}
Built-in entity types are marked with a Cortex logo. Hover over the logo to see a "Powered by Cortex" banner. Any other types in the list are custom entity types created for your workspace.

<img src="/files/B6MeZaglbUSl9Rde7d96" alt="The &#x27;Powered by Cortex&#x27; icon appears next to a built-in entity in the Entities list." data-size="original">
{% endhint %}

## Validating an entity schema for a custom entity type

1. From the main sidebar, expand **Catalogs**, then select **All entities**.
2. Select the **Entity types** tab.
3. Select an entity type.
4. Select the **Schema linter** tab.
5. In the text editor, paste in your entity's JSON schema to verify that it's properly formatted for this entity type.
   * On the right side of the page, click **Show example** to see an example of how the schema should be formatted.
   * If you want to use the example as a starting point, click **Copy example**, then paste it into the text editor.
6. Click **Validate Schema**.

## Using custom entity types or custom data

In some instances, you may want to use custom data instead of a custom entity type. This is recommended if you need more flexibility for these entity types; they may not always require specific metadata.

{% hint style="info" %}
A custom entity type's metadata appears on an [entity's details page](/ingesting-data-into-cortex/entities-overview/entities/details), but custom data appears in the **Custom Data** sidebar.
{% endhint %}

It's possible to create an entity type with an empty properties schema:

```json
{
  "type": "object",
    "required": []
    "properties": {}
}
```

This entity type appears in catalogs, but its entities are not validated against certain specs. Use custom data to define those properties instead.

Schemas enforce static properties consistently across all entities, while custom data lets users augment and update attributes as needed.


# Defining dependencies

In Cortex, you can define outgoing dependencies on other entities, and for some integrations Cortex can discover them automatically. Defining dependencies lets you notify owners when a dependency deprecates its API or ships a backwards-incompatible change, and lets you visualize dependencies in a [relationship graph](/ingesting-data-into-cortex/entities-overview/entities/relationship-graph). Incoming dependencies are inferred automatically from your outgoing definitions.&#x20;

## Automated dependency notifications

{% hint style="info" %}
This feature is available in beta. Please reach out to your Cortex Customer Success Manager for access.
{% endhint %}

Cortex can automatically discover dependencies from the following integrations:

* [AWS](/ingesting-data-into-cortex/integrations/aws)
* [Azure Resources](/ingesting-data-into-cortex/integrations/azureresources)
* [Datadog](/ingesting-data-into-cortex/integrations/datadog)
* [Dynatrace](/ingesting-data-into-cortex/integrations/dynatrace)
* [Google Cloud](/ingesting-data-into-cortex/integrations/google)
* [New Relic](/ingesting-data-into-cortex/integrations/newrelic)

When a dependency deprecates its API or makes backwards incompatible changes, Cortex surfaces these issues via these methods:

* Breaking API changes are listed in your Cortex workspace. To access:
  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 **Breaking API changes**.
* When a PR introduces breaking OpenAPI changes that affect downstream dependencies Cortex knows about, Cortex attempts to comment on it automatically.
* If a breaking change is merged to the default branch, Cortex alerts dependency owners via Slack that a breaking change was merged.

## Defining dependencies

Users or API keys with the `Edit Entities` permission can define dependencies.

Dependencies can be defined in the Cortex UI, manually via an entity's YAML descriptor, or from the API.

### Defining dependencies via the Cortex UI

1. Navigate to the entity where you need to define a dependency.
2. In the upper-right corner of the [entity's details page](/ingesting-data-into-cortex/entities-overview/entities/details), click **Configure entity**.
3. From the left entity sidebar, click **Dependencies**.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/kNieUvOyokdsX1qNZu6T" alt="The &#x27;Dependencies&#x27; tab in the left entity sidebar." width="375"><figcaption></figcaption></figure></div>
4. Click **Add entity**.
5. In the **Dependency** sidebar, do the following:
   1. From the **Entity** drop-down menu, select an entity (required).
   2. From the **Endpoints** drop-down menu, select an endpoint. For an endpoint to populate in this dropdown, it must first be defined as a path in the entity's YAML file. See [Setting an endpoint for a dependency](#setting-an-endpoint-for-a-dependency) for more information.
   3. From the **Description** drop-down menu, enter a description for the dependency.
6. Click **Add**.

#### **Setting an endpoint for a dependency**

When manually defining a dependency, you can only select endpoints from the dropdown that are already defined as paths in the target entity's YAML file. For example, to make the `GET /v1/payments` and `POST /v1/refunds` endpoints selectable, the payments service would need the following in its OpenAPI spec:

```yaml
openapi: 3.0.1
info:
  title: Payments Service
  description: Handles payment processing and refunds
  x-cortex-tag: payments-service
  x-cortex-type: service
paths:
  /v1/payments:
    get:
      description: List payments
      responses:
        "200":
          description: A list of payments
      deprecated: false
  /v1/refunds:
    post:
      description: Issue a refund
      requestBody:
        description: Refund details
        required: true
      responses:
        "201":
          description: Refund created
      deprecated: false
```

In the UI, the paths now appear in the **Endpoints** drop-down menu:

<div align="left" data-with-frame="true"><figure><img src="/files/KOfMjPoPKxEOPC5RPufC" alt="Paths in the Endpoints drop-down menu." width="252"><figcaption></figcaption></figure></div>

### **Defining dependencies in the entity descriptor**

The `x-cortex-dependency` field allows you to define a list of outgoing dependencies. A dependency should be directed towards an outgoing service or resource, or more granularly, to a specific endpoint of that entity.

```yaml
info:
  x-cortex-dependency:
    - tag: braavos
      method: GET
      path: /2.0/users/
      description: Ensure user has payment information configured
      metadata:
        tags:
          - billing
          - identity
        prod: true
```

<table><thead><tr><th width="121.8359375">Field</th><th width="277.703125">Description</th><th align="center">Required?</th></tr></thead><tbody><tr><td><strong>tag</strong></td><td>The <code>tag</code> of the entity this entity depends on, i.e. the callee. See <code>x-cortex-tag</code></td><td align="center"><i class="fa-check">:check:</i></td></tr><tr><td><strong>method</strong></td><td>HTTP method <em>if</em> depending on a specific endpoint</td><td align="center">Required if <code>path</code> is present</td></tr><tr><td><strong>path</strong></td><td>The actual endpoint this dependency refers to</td><td align="center">Required if <code>method</code> is present</td></tr><tr><td><strong>description</strong></td><td>A description of the dependency.</td><td align="center"><i class="fa-x">:x:</i></td></tr><tr><td><strong>metadata</strong></td><td>JSON metadata tags for the relationship. Supports arbitrary objects.</td><td align="center"><i class="fa-x">:x:</i></td></tr></tbody></table>

### **Defining dependencies via the API**

See the [API docs](/api/readme/dependencies) for authentication details.

{% hint style="warning" %}
YAML is the source of truth. If a dependency has already been set through the `cortex.yaml`, the API returns an error.
{% endhint %}

Endpoints are optional. A dependency optionally references an endpoint (`method` and `path`) of the callee, and this must already be defined in the callee's `cortex.yaml` within the `paths` field. If no endpoint is referenced it is assumed that the caller depends on **all** endpoints of the callee.

For all requests, `method` and `path` are optional; however, if one is present, the other must also be present.

When interacting with an existing dependency, the `method` and `path` must be specified correctly to identify it.

<table><thead><tr><th>Field</th><th width="351">Description</th><th align="center">Required?</th></tr></thead><tbody><tr><td><strong>callerTag</strong></td><td>The <code>tag</code> of the caller.</td><td align="center"><i class="fa-check">:check:</i></td></tr><tr><td><strong>calleeTag</strong></td><td>The <code>tag</code> the caller depends on.</td><td align="center"><i class="fa-check">:check:</i></td></tr><tr><td><strong>method</strong></td><td>HTTP method <em>if</em> depending on a specific endpoint</td><td align="center">Required if <code>path</code> is present</td></tr><tr><td><strong>path</strong></td><td>The actual endpoint (as defined in the OpenAPI file) the caller depends on</td><td align="center">Required if <code>method</code> is present</td></tr><tr><td><strong>description</strong></td><td>A description of the dependency.</td><td align="center"><i class="fa-x">:x:</i></td></tr><tr><td><strong>metadata</strong></td><td>JSON metadata tags for the relationship. Supports arbitrary objects.</td><td align="center"><i class="fa-x">:x:</i></td></tr></tbody></table>

```json
{
  "callerTag": "payments-service",
  "calleeTag": "braavos",
  "path": "/2.0/users/",
  "method": "GET",
  "description": "Ensure user has payment information configured",
  "metadata": {
    "tags": ["billing", "identity"],
    "prod": true
  }
}
```

#### **Creating a dependency**

`POST /api/v1/catalog//dependencies/?method=&path=`

```json
{
  "description": "Ensure user has payment information configured",
  "metadata": 
}
```

#### **Retrieving a dependency**

`GET /api/v1/catalog//dependencies/?method=&path=`

#### **Updating a dependency**

`PUT /api/v1/catalog//dependencies/?method=&path=`

{% hint style="warning" %}
`PUT` replaces the entire object. The request body is considered a modified version of the already existing entity. Leaving a field out of the JSON is interpreted as `null`.
{% endhint %}

```json
{
  "description": "Ensure user has payment information configured",
  "metadata": 
}
```

#### **Deleting a dependency**

`DELETE /api/v1/catalog//dependencies/?method=&path=`

#### **Creating or updating dependencies in bulk**

`PUT /api/v1/catalog/dependencies`

{% hint style="warning" %}
`PUT` replaces the entire object The request body is considered a modified version of the already existing entity. Leaving a field out of the JSON is interpreted as `null`.
{% endhint %}

```json
{
  "values": {
    "my-service": [
      {
        "tag": "braavos",
        "path": "/2.0/users/",
        "method": "GET",
        "description": "ensure user has payment information configured",
        "metadata": 
      }
    ],
    "my-other-service": [
      {
        "tag": "payments-service",
        "path": "/1.0/widget/",
        "method": "GET",
        "description": "get widget",
        "metadata": 
      }
    ]
  }
}
```

## Syncing dependencies manually

Users with the `Enable Entity Dependency Discovery` permission can manually sync dependencies.

{% hint style="info" %}
Cortex automatically syncs AWS dependencies every day at 8:00 a.m. UTC. All other dependencies sync at 12:00 a.m. UTC.
{% endhint %}

**To sync dependencies manually**:

1. From the main sidebar, expand **Tools**, then select **Relationship graphs**.
2. In the upper-right corner of the page, click the **overflow menu icon**, then click **Sync dependencies**.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/ijwIKjYJkReTbt5izNTZ" alt="The overflow menu icon in the upper-right corner of the page."><figcaption></figcaption></figure></div>

## Troubleshooting and FAQ

**What if I have multiple dependency sources?**

When leveraging multiple dependency sources (such as Datadog and a catalog entity's YAML), all the sources are merged together and de-duplicated.

For example, if an entity YAML indicates `X->Y` and Datadog indicates `X->Y` and `X->Z`, two edges are presented (`X->Y` and `X->Z`).


# Entity details page

Each entity has a dedicated details page that centralizes all related data, helping developers stay focused by reducing context switching. To open an entity's details page, click its name either while browsing a catalog or from the **Catalogs > All entities** page. From here you can quickly access key information:

* **Active incidents** - Any ongoing incidents are surfaced at the top of the page for immediate visibility.
* **Sidebar** - [Customize which metadata](#configuring-the-entity-metadata-sidebar) appears here by pinning the information most relevant to you. Supported data includes on-call schedules, owners, Slack or Microsoft Teams channels, groups, repositories, entity relationships, doc links, project management, custom data, and code quality.

{% hint style="success" %}
During an incident, the entity details page surfaces everything you need in one place: the active incident, owners and on-call contacts, the relevant Slack channel, affected dependencies, and recent deploys.
{% endhint %}

{% hint style="info" %}
Fields only appear in the overview if data is available. For example, the **Slack channels** field won't display unless you have the Slack integration configured.
{% endhint %}

## Locating an entity's unique identifiers

The [Cortex tag](/ingesting-data-into-cortex/entities-overview/entities#cortex-tag) and the [Cortex ID](/ingesting-data-into-cortex/entities-overview/entities#cortex-id) are displayed below the entity's name.

<div align="left" data-with-frame="true"><figure><img src="/files/Bk3B3XWmSABGIfdLTKeW" alt="The entity&#x27;s unique identifiers appear below its name." width="400"><figcaption></figcaption></figure></div>

## Configuring the entity's sidebars

Each entity details page includes two sidebars—the entity details sidebar on the left and the entity metadata sidebar on the right—each serving a distinct purpose.

### Configuring the entity details sidebar

The entity details sidebar appear on the left side of every entity page. It provides a deeper view into the entity's recent deploys, events, security vulnerabilities, monitoring metrics, and more, giving you the context needed to resolve incidents quickly.

The entity details sidebar contains the following information about the entity:

#### Overview categories

* **Relationships** - See how an entity connects to the rest of your catalog including domain hierarchy, team hierarchy, dependencies, and any custom relationship types you've defined. See [Defining relationship types](/ingesting-data-into-cortex/entities-overview/entities/defining-relationship-types) and [Viewing relationships on an entity page](/ingesting-data-into-cortex/entities-overview/entities/defining-relationship-types#view-relationships-on-entity-pages).
* **API explorer** - Pulls from [API documentation](/ingesting-data-into-cortex/entities-overview/entities/external-docs) added to your entity.
* **Events** - A list of recent events sourced from [deploys](/ingesting-data-into-cortex/entities-overview/entities/deploys), [AWS ECS](/ingesting-data-into-cortex/integrations/aws), [Azure DevOps](/ingesting-data-into-cortex/integrations/azuredevops), [GitHub](/ingesting-data-into-cortex/integrations/github), [GitLab](/ingesting-data-into-cortex/integrations/gitlab), [Kubernetes](/ingesting-data-into-cortex/integrations/kubernetes), [Opsgenie](/ingesting-data-into-cortex/integrations/opsgenie), [PagerDuty](/ingesting-data-into-cortex/integrations/pagerduty), [Sentry](/ingesting-data-into-cortex/integrations/sentry), and [Snyk](/ingesting-data-into-cortex/integrations/snyk).
* **Links & docs** - [Documentation links](/ingesting-data-into-cortex/entities-overview/entities/external-docs) you have added to the entity, along with documentation pulled from the related repository.
* **Owners** - See the teams who own the entity, the related Slack or Microsoft Teams channels, and a list of team members. Learn more about [defining entity owners](/ingesting-data-into-cortex/entities-overview/entities/ownership).
* **Entity YAML** - View the [entity YAML](/ingesting-data-into-cortex/entities-overview/entities#defining-entities-via-yaml-file) that defines the selected entity.
  * If you have [GitOps editing](/configure/gitops#step-1-disable-ui-editing) enabled for this entity, and you have the `View GitOps logs` permission, this page displays the source of the YAML file and a preview of the latest GitOps log.

#### Cortex features

* **Scorecards** - A list of any [Scorecards](/standardize/scorecards) that are in progress where this entity is being scored. Additionally, see the average score, median score, and a graph showing the entity's scores over time.
  * Above the *Scorecard* section, you can choose which scores to include in calculations if the entity is in a hierarchy:
    * **Domains** - Click **This entity only** to view only the scores that apply to the domain you are viewing. Select **Include entity's children** to include both the parent domain and its child entities in the score calculations.
    * **Entities with a custom relationship type** - Click **This entity only** to view only the scores that apply to the entity you are viewing. Click **\[Relationship type] only** to include both the parent and its child entities in the score calculations.
    * **Teams** - Click **This entity only** to view the scores that apply only to the team you are viewing. Click **Include entity's children** to include scores for the team, the team's children, entities owned by the team, and entities owned by the team's children.
* **Initiatives** - A list of all active [Initiatives](/improve/initiatives) for this entity, including the Scorecard's current level and the due date of the Initiative.
* **Workflows** - A list of [Workflows](/streamline/workflows) that include this entity.
  * If you are a designated approver for any pending Workflows, they will appear at the top of this page. You can also view recently run Workflows and trigger any related Workflows from here.

#### Connections

The *Connections* section displays integration data grouped by context. Once you configure integrations, data appears in the following sections on the entity page:

* **CI/CD** - Pulls from [deploys API](/ingesting-data-into-cortex/entities-overview/entities/deploys), [Azure DevOps](/ingesting-data-into-cortex/integrations/azuredevops), [Bitbucket](/ingesting-data-into-cortex/integrations/bitbucket), [Buildkite](/ingesting-data-into-cortex/integrations/buildkite), [CircleCI](/ingesting-data-into-cortex/integrations/circleci), [GitHub](/ingesting-data-into-cortex/integrations/github), and [GitLab](/ingesting-data-into-cortex/integrations/gitlab).
* **Cloud** - Pulls from [AWS](/ingesting-data-into-cortex/integrations/aws) and [Kubernetes](/ingesting-data-into-cortex/integrations/kubernetes). The **AWS** section appears only on entities that have an `AWS::ECS::Service` resource linked in their `x-cortex-infra` block. See [Viewing AWS data on an entity](/ingesting-data-into-cortex/integrations/aws/using-the-integration-for-aws).
* **Code quality** - Pulls from [Codecov](/ingesting-data-into-cortex/integrations/codecov) and [SonarQube](/ingesting-data-into-cortex/integrations/sonarqube).
* **Custom data & metrics** - Pulls from [custom data](/ingesting-data-into-cortex/entities-overview/entities/custom-data) and [Eng Intelligence custom metrics](/improve/eng-intelligence/custom-metrics).
* **Dashboard** - Pulls from [charts](/ingesting-data-into-cortex/entities-overview/entities/external-docs#embed-dashboards) configured in the entity's YAML file for [Datadog](/ingesting-data-into-cortex/integrations/datadog), [Grafana](/ingesting-data-into-cortex/integrations/grafana), and [New Relic](/ingesting-data-into-cortex/integrations/newrelic).
* **Error tracking** - Pulls from [BugSnag](/ingesting-data-into-cortex/integrations/bugsnag), [Rollbar](/ingesting-data-into-cortex/integrations/rollbar), and [Sentry](/ingesting-data-into-cortex/integrations/sentry).
* **Feature flags** - Pulls from [LaunchDarkly](/ingesting-data-into-cortex/integrations/launchdarkly).
* **Observability** - Pulls from [Coralogix](/ingesting-data-into-cortex/integrations/coralogix), [Datadog](/ingesting-data-into-cortex/integrations/datadog), [Dynatrace](/ingesting-data-into-cortex/integrations/dynatrace), [Google Observability Cloud](/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](/ingesting-data-into-cortex/integrations/splunk-observability) (formerly SignalFX), and [Sumo Logic](/ingesting-data-into-cortex/integrations/sumologic).
* **On-call & incidents** - On-call information from [Opsgenie](/ingesting-data-into-cortex/integrations/opsgenie), [PagerDuty](/ingesting-data-into-cortex/integrations/pagerduty), [Splunk On-Call](/ingesting-data-into-cortex/integrations/splunk-oncall) (formerly VictorOps), and [xMatters](/ingesting-data-into-cortex/integrations/xmatters), and incidents pulled from [incident.io](/ingesting-data-into-cortex/integrations/incidentio), [PagerDuty](/ingesting-data-into-cortex/integrations/pagerduty), [FireHydrant](/ingesting-data-into-cortex/integrations/firehydrant), and [Rootly](/ingesting-data-into-cortex/integrations/rootly).
* **Packages** - Pulls from the [packages API](/api/readme/packages) and any packages automatically discovered from your configured git repositories.
* **Project management** - Pulls from [Azure DevOps](/ingesting-data-into-cortex/integrations/azuredevops), [ClickUp](/ingesting-data-into-cortex/integrations/clickup), [GitHub](/ingesting-data-into-cortex/integrations/github), [GitLab](/ingesting-data-into-cortex/integrations/gitlab), and [Jira](/ingesting-data-into-cortex/integrations/jira).
* **Security** - Pulls from [Apiiro](/ingesting-data-into-cortex/integrations/apiiro), [Checkmarx](/ingesting-data-into-cortex/integrations/checkmarx), [Codecov](/ingesting-data-into-cortex/integrations/codecov), [GitHub](/ingesting-data-into-cortex/integrations/github), [GitLab](/ingesting-data-into-cortex/integrations/gitlab), [Mend](/ingesting-data-into-cortex/integrations/mend), [Semgrep](/ingesting-data-into-cortex/integrations/semgrep), [Snyk](/ingesting-data-into-cortex/integrations/snyk), [SonarQube](/ingesting-data-into-cortex/integrations/sonarqube), [Veracode](/ingesting-data-into-cortex/integrations/veracode), and [Wiz](/ingesting-data-into-cortex/integrations/wiz).
* **Version control** - Pulls 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).

#### Plugins

The *Plugins* section displays [plugins](/streamline/plugins) that are relevant to this entity.

### Configuring the entity metadata sidebar

The entity metadata sidebar appears on the right side of every entity page. You can control which metadata categories are displayed, reorder them, and apply the same layout across multiple entity types at once.

#### Expanding or collapsing the metadata sidebar

Click the **arrow icon** in the bottom-right corner to expand or collapse the metadata sidebar.

<div align="left" data-with-frame="true"><figure><img src="/files/B0vSTwUs66DgX7xEI43O" alt="The arrow icon in the bottom-right corner of the page." width="400"><figcaption></figcaption></figure></div>

#### Customizing the metadata sidebar

Users who are admins or who have the `Edit Entity Types` permission can customize the metadata sidebar.

{% hint style="success" %}
As of July 2026, **Domains** now appear in the **Relationships** tab. When viewing an entity, select **Relationships** from the left entity details sidebar.
{% endhint %}

1. In the bottom-right corner of the metadata sidebar, click the **Configure entity sidebar** icon.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/2okzb7JdlzJ4bGEjf5Bn" alt="The &#x27;Configure entity&#x27; icon in the bottom-right corner of the page." width="400"><figcaption></figcaption></figure></div>
2. To reorder a category, hover over the **grip icon** and drag it to the desired position. To hide a category, click the **eye icon** next to it. Repeat as necessary.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/tVBdIDRt4NNPPVI3X2bw" alt="The Grip icon next to an entity." width="127"><figcaption></figcaption></figure></div>
3. From the **Apply layout to entity types** drop-down menu, select which entity types to apply this configuration to.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/2WpKL4SUmpKqL9o4qLcc" alt="The Apply layout to entity types drop-down  menu in the bottom-right corner of the page." width="127"><figcaption></figcaption></figure></div>
4. Click **Apply to workspace**.

## Customizing entity page plugin tabs <a href="#pinning-plugins" id="pinning-plugins"></a>

Users with the `Edit Entities` permission can pin, reorder, and hide plugins on an entity's details page. Plugins pinned this way appear as tabs at the top of the page, either on a single entity or across all entities of the same type.

Before a plugin can be pinned, it must be configured to include the relevant entity type in its context. For example, to pin a plugin on a Teams entity page, include the `team` entity type when registering the plugin in Cortex.

{% hint style="info" %}
System-level tabs are always visible by default but can be reordered. Most entity types only have the **Overview** tab, though some have more. For example, Teams entity pages include both the **Overview** and **Entities** tabs. Applicable plugins are also visible by default and are appended to any existing tab configuration.
{% endhint %}

Tab configurations saved at the individual entity level take precedence over configurations saved at the entity-type level. For example, if you customize tabs on the *Engineering* Teams page and later save a different tab configuration for all `team` entities, the *Engineering* page keeps its original configuration.

**To pin and reorder plugins**:

1. Navigate to the entity.
2. On the entity details page, click the **gear icon**. The **Edit tabs** side panel opens.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/yus6BjEvgL4ig8VSCDlk" alt="The Gear icon near the upper-right corner of the page." width="400"><figcaption></figcaption></figure></div>

   <div data-gb-custom-block data-tag="hint" data-style="info" class="hint hint-info"><p>When there are too many pinned tabs to fit across the page, the <strong>gear icon</strong> moves into the <em>Overflow</em> menu. Click the <strong>Overflow menu icon</strong> to access it.</p></div>
3. To reorder a plugin, hover over the **grip icon** and drag it to the desired position. To hide a plugin, click the **eye icon** next to it. Repeat as necessary. There is no limit to the number of plugins you can pin to an entity page. If you have more pinned plugins than can fit across the page, the remaining tabs are accessible via the **Overflow** menu.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/nUhEdHmYlJfmkv4xZh8H" alt="The Grip icon next to a plugin." width="113"><figcaption></figcaption></figure></div>
4. To apply the layout to all entities of the same type, select the **Apply to entities of type service** checkbox.
5. Click **Save**. The plugin is pinned to the top of the entity details page.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/lCMnkJxyVjw7ZKOhoHhD" alt="The pinned plugin tabs." width="400"><figcaption></figcaption></figure></div>


# Defining ownership

Overview of ownership in Cortex

Every entity in your catalog should have a clear answer to the question: *who is responsible for this?* Ownership is what makes that answer reliable.

In practice, ownership does more than assign a name to an entity. It's the connective tissue between your catalog and your workflows. It determines who gets notified when an incident fires, who's accountable when a Scorecard degrades, and who needs to act when verification lapses. Without it, alerts go unanswered, reviews stall, and gaps in your platform go unnoticed.

Cortex gives you several ways to establish ownership:

* Automated recommendations based on repository activity
* Definitions pulled from your identity providers and version control integrations
* Manual assignment in the UI
* Inheritance from parent entities in your hierarchy.

However you get there, the goal is the same: every entity has an accountable owner, and that owner is always current.

{% hint style="success" %}
Avoid inefficient manual processes by using [Cortex's Ownership tool](/ingesting-data-into-cortex/entities-overview/entities/ownership/assigning-owners-to-entities#assigning-ownership-via-cortex-recommendations) to solve entity ownership quickly. Cortex automatically predicts entity owners so developers can skip the guesswork and reach the right person immediately.
{% endhint %}

## Viewing entity owners

When viewing an entity, the owners appear in the metadata bar on the right side of the page:

<div align="left" data-with-frame="true"><figure><img src="/files/KMVIx1mhVgddqGx08GL5" alt="The Owners section in an entity&#x27;s metadata sidebar." width="563"><figcaption></figcaption></figure></div>

If the entity is owned by a team, click the team name to open the team's entity page, which lists its members and owned entities. If owned by an individual, Cortex displays the user's email. For information on assigning owners, refer to

## Viewing entities without owners

There are a few ways to find entities in your catalog that don't have owners yet:

* Use the [Ownership tool](/ingesting-data-into-cortex/entities-overview/entities/ownership/assigning-owners-to-entities#assigning-ownership-via-cortex-recommendations) to see unowned entities and Cortex's automated recommendations for owners
* View the [Executive Report](/improve/reports/executive-report), which lists unowned entities
* Run an [Ownership Verification Scorecard](/standardize/scorecards/create#scorecard-templates), which adds tasks to your homepage for any entities still missing owners


# Assigning owners to entities

Cortex supports three ways to assign owners to an entity: accepting an automated recommendation, defining owners in the entity descriptor YAML, or adding them directly in the UI. For most teams, a combination of all three is common; automated recommendations to tackle unowned entities at scale, YAML for entities managed through GitOps, and the UI for quick edits.

## Types of owners

Owners can be defined as:

* **A team** (recommended)
  * If you link a `group` from an external platform (such as Okta), Cortex automatically updates team membership when someone leaves your organization and is removed from your identity provider.
* **An individual user**
* **Fallback or append settings** configured in an entity's hierarchy

## Methods for assigning ownership

Owners can be assigned:

* By accepting Cortex's automated recommendations for owners, based on repository activity
* By pulling information from third-party integrations in the [entity descriptor YAML](/ingesting-data-into-cortex/entities-overview/entities#defining-entities-with-yaml)
  * Ownership can also be inherited via [fallback or append configuration](/ingesting-data-into-cortex/entities-overview/entities/ownership/ownership-inheritance)
* Directly in the Cortex UI
* Automatically if Cortex detects that an entity is owned by a team that does not yet exist in Cortex
  * If an entity's YAML references a team, but that team doesn't have a corresponding entry within Cortex, Cortex automatically creates the team. A label next to the team name denotes that team was **Automatically created by Cortex**.

### Assigning ownership via Cortex recommendations

{% hint style="info" %}
**Ownership tool preview**

Not seeing the results you expect? This is an early version of the Ownership tool. Please submit feedback [via this form](https://docs.google.com/forms/d/e/1FAIpQLSdURosGQhMnmMCF7FA66v9DOdnk5rOSoK1SaUVGjpOy4ywt5g/viewform). Note the following considerations:

* This feature is supported for entities associated with a repository in GitHub, GitLab, or Azure DevOps. Mapping is done on a per repository basis, so mapping teams owners to file paths within a monorepo is not supported.
* You must have teams configured in Cortex and team members must be [identity-mapped](/configure/settings/managing-users/identity-mapping) in order for Cortex to provide recommendations. The more teams and people you have mapped, the better the recommendations!
* Cortex analyzes the last six (6) months of data, so if a repository has not had code changes within that time period, we will not have a recommendation.
* To accept or reject the recommended owner, the user must have the `Edit Entities` permission.
* If you are using GitOps, you can view recommendations, but you cannot accept them from the UI.
  {% endhint %}

Cortex analyzes repositories to automatically recommend team owners for unowned entities.

When Cortex has an ownership recommendation for an entity, it surfaces in the following places: the Ownership tool (**Tools > Ownership**), the Owners section of the entity details page overview, the Owners sidebar on the entity details page, and the import flow when adding entities.

#### **Reviewing ownership recommendations per entity**

To review and accept ownership recommendations, three conditions must be met: UI editing must be enabled for the entity type, the user must have entity-level access via RBAC or fine-grained access control, and the user must have the `Edit Services` and `Edit Catalog` roles.

1. Navigate to the [entity details page](/ingesting-data-into-cortex/entities-overview/entities/details) of the entity to which you want to assign ownership.
2. In the upper-right corner, click **Configure entity**.
3. From the left entity details sidebar, click **Owners**.
4. Review the suggested owners. To accept a recommendation, select the checkbox next to the recommended owner, then click **Add owners**.

#### **Reviewing ownership recommendations in bulk**

Users with edit access to all entities can review and accept ownership recommendations in bulk. Users with edit access to only some entities can accept recommendations individually from each entity's details page.

1. From the main sidebar, expand **Tools**, then select **Ownership**. A list of recommendations for ownership is displayed.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/Ba9zzosgzcamkEEs0ZiT" alt="The Ownership page in Cortex." width="375"><figcaption></figcaption></figure></div>
2. Select the checkboxes next to the entities for which you want to accept ownership recommendations. Use the **Team recommendation** drop-down menu to add or remove teams.
3. At the top of the list, click **Accept recommendations**.

### Assigning ownership via an entity descriptor

Use the `x-cortex-owners` field to define owners directly in your entity's YAML. Each owner is either a `group` (a team from Cortex or a connected integration) or an individual identified by `email`.&#x20;

Each owner entry requires the `type` field, set to either `group` or `email`. For `group` owners, the `name` and `provider` fields are also required. For `email` owners, the `email` field is required.

Cortex recognizes groups from the following integrations: [Azure Active Directory](/ingesting-data-into-cortex/integrations/entraid), [Azure DevOps](/ingesting-data-into-cortex/integrations/azuredevops), [BambooHR](/ingesting-data-into-cortex/integrations/bamboohr), [GitHub](/ingesting-data-into-cortex/integrations/github), [GitLab](/ingesting-data-into-cortex/integrations/gitlab), [Google](/ingesting-data-into-cortex/integrations/google), [Okta](/ingesting-data-into-cortex/integrations/okta), [Opsgenie](/ingesting-data-into-cortex/integrations/opsgenie), [ServiceNow](/ingesting-data-into-cortex/integrations/servicenow), and [Workday](/ingesting-data-into-cortex/integrations/workday).

```yaml
x-cortex-owners:
  - type: group
    name: platform-engineering        # x-cortex-tag of the Cortex team
    provider: CORTEX
  - type: group
    name: cortexapps/payments-team    # GitHub org/team slug
    provider: GITHUB
  - type: group
    name: payments-oncall             # Opsgenie team name
    provider: OPSGENIE
  - type: email
    email: maya.chen@acme.com      # individual fallback owner
    description: Primary escalation contact
```

The `provider` field tells Cortex which system the group comes from. Supported values are: `ACTIVE_DIRECTORY`, `AZURE_DEVOPS`, `BAMBOO_HR`, `CORTEX` (use for teams defined natively in Cortex, not synced from an external integration), `GITHUB`, `GITLAB`, `GOOGLE`, `OKTA`, `OPSGENIE`, `SERVICE_NOW`, and `WORKDAY`.

The `name` field is case-sensitive. What it refers to depends on the provider:

* For `CORTEX` - The `x-cortex-tag` of the team in Cortex
* For all other providers - The upstream identifier for the group in that integration (e.g. an Okta group name, a GitHub `org/team-slug`)

The `description` field is optional on any owner entry and is purely for human reference.

### Assigning ownership via the Cortex UI

Users with the `Edit Entities` or `Edit Catalog` role can assign ownership via the Cortex UI.

1. From the main sidebar, expand **Catalogs**, then select **All entities**.
2. Do one of the following:
   * Select the **All** tab to search and filter across all of your organization's entities.
   * Select the **Mine** tab to search and filter only the entities you own.
   * Note that Cortex saves your selection and restores it the next time you open this page.
3. Select the entity whose ownership you want to edit.
4. In the upper-right corner, click **Configure entity**.
5. From the left entity details sidebar, click **Owners**.
6. Do one or both of the following:
   1. To assign a team ownership:
      1. Locate the **Teams** section, then click **Add**.<br>

         <div align="left" data-with-frame="true"><figure><img src="/files/XvLmV0K4PmFSNIpSkM7Q" alt="The Add button next to Teams." width="375"><figcaption></figcaption></figure></div>
      2. In the **Add Teams** side panel, select the team from the drop-down menu.
      3. Optionally, enter a description for the team.
      4. Click **Add**.
   2. To assign an individual user ownership:
      1. Locate the **Users** section, then click **Add**.<br>

         <div align="left" data-with-frame="true"><figure><img src="/files/Ic8RfcfZ8RBljfkuYuIs" alt="The Add button next to Users." width="375"><figcaption></figcaption></figure></div>
      2. In the **User** side panel, do one of the following:
         1. Select a Cortex user from the drop-down menu. To find a user not shown in the list, use the **Search** field.
         2. To add a user who is not listed in Cortex, enter their email address into the **Email address** field. The drop-down populates with the user's email address.
      3. Optionally, enter a description for the user.
      4. Click **Add**.


# Ownership inheritance

Rather than assigning owners to every entity individually, you can define ownership at the domain level and have it propagate to child entities. This is useful for large catalogs where many entities share a common accountable team.

Inheritance is configured per owner using the `inheritance` field in the `x-cortex-owners` block. If omitted, it defaults to `NONE`.

```yaml
openapi: 3.0.1
info:
  title: Payments Platform
  description: Domain covering all payments-related services and resources.
  x-cortex-tag: payments-platform
  x-cortex-type: domain
  x-cortex-owners:
    - type: group
      name: payments-leads             # owns this domain directly; no inheritance
      provider: CORTEX
      inheritance: NONE
    - type: group
      name: platform-engineering       # appended as owner on all child entities
      provider: CORTEX
      inheritance: APPEND
    - type: group
      name: cortexapps/payments-team   # fallback if a child has no other owners
      provider: GITHUB
      inheritance: FALLBACK
```

The three `inheritance` values behave as follows:

* **`APPEND`** - This owner is added to the owner list of every child entity, regardless of whether the child already has owners.
* **`FALLBACK`** - This owner is assigned to a child entity only if that child has no other valid owners (including other fallbacks). Note that `FALLBACK` applies to children only, not to the domain itself.
* **`NONE`** - This owner belongs to the domain but does not propagate to children.

You can also configure inheritance in the Cortex UI when [creating a domain](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/domains) or [defining a relationship type](/ingesting-data-into-cortex/entities-overview/entities/defining-relationship-types).

## **Viewing the source of an inherited owner**

When ownership is layered across a hierarchy, it can be hard to tell why a particular team appears as an owner on a given entity. To trace it:

1. Navigate to the [entity details page](/ingesting-data-into-cortex/entities-overview/entities/details) of the entity.
2. In the [metadata sidebar](/ingesting-data-into-cortex/entities-overview/entities/details#configuring-the-entity-metadata-sidebar), locate the **Owners** section.
3. Next to an owner, click the **Inheritance chain** icon.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/IT48s5PQv4qcBFfIDPbN" alt="The &#x27;Inheritance chain icon&#x27; is found within the Owners section in the metadata sidebar." width="375"><figcaption></figcaption></figure></div>

Cortex shows the source entity, the relationship type, and the rule (`APPEND` or `FALLBACK`) that caused the owner to propagate. The icon only appears for inherited owners; direct owners defined on the entity itself have no chain to display.

## Automatic discovery for AWS

{% hint style="info" %}
Cortex syncs ownership from AWS every day at 6 am UTC.
{% endhint %}

If your AWS resources are tagged with an `owner` tag, Cortex can use those tags to assign ownership automatically.

To enable this:

1. In AWS, tag your AWS resources with `owner: <cortex-team-tag>`, where the value matches the `x-cortex-tag` of the corresponding Cortex team.
2. In Cortex:
   1. Click your avatar in the bottom-left corner, then select **Settings**.
   2. From the **Settings** menu, scroll to the **Identity mappings** section.
   3. Select **AWS**.
   4. Enable **Sync ownership from AWS**.


# Viewing and managing ownership

Once your catalog has owners assigned, Cortex gives you several ways to slice that data: by individual, by team, or across a team hierarchy. This page covers how to find the entities you own, filter by team, and remove ownership that's no longer accurate.

## Viewing entities you own

1. From the main sidebar, expand **Catalog**, the select **All entities**.
2. Select the **Mine** tab. A list of entities you own is displayed.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/lLsQwn4PJVMZoTOY5i5g" alt="The Entities page showing all entities owned by the user." width="375"><figcaption></figcaption></figure></div>

### Viewing child team ownership

1. From the main sidebar, expand **Catalog**, the select **All entities**.
2. Select the **Mine** tab.
3. At the top of the list, click **Display**.
4. Toggle on **Include child teams**.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/EkxKL0DE5Uy9KNvTDHX5" alt="The &#x27;Include child teams&#x27; option, toggle on." width="375"><figcaption></figcaption></figure></div>
5. Click **Done**.

## Viewing a team's owned entities

1. From the main sidebar, expand **Catalog**, the select **All entities**.
2. Select the **All** tab.
3. At the top of the list, click **Filter**.
4. In the **Filter** window, click **Teams**.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/pPSxVMRsBVaWlfM0TbDf" alt="The &#x27;Teams&#x27; option in the Filter window." width="375"><figcaption></figcaption></figure></div>
5. Select a team or teams from the drop-down menu.
6. Click **Apply**.

### Viewing entities owned by all teams within a hierarchy

Teams can exist [within hierarchies](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/teams/viewing-teams#understanding-hierarchies). To view a list of entities owned by the parent team and all children teams in the hierarchy:

1. Navigate to the parent team's page.
2. Select the **Entities** tab.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/u1rXXNDZyQbOrMsbphGs" alt="The &#x27;Entities&#x27; tab on a team&#x27;s page." width="375"><figcaption></figcaption></figure></div>
3. At the top of the list, click **Display**.
4. Toggle on **Inherited Children**.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/p5L7nwud5vWI19aFJbe3" alt="The &#x27;Inherited children&#x27; option toggled on." width="375"><figcaption></figcaption></figure></div>
5. Click **Done**.

The list displays all entities owned by the parent and its children teams. Note that this setting does not persist when you navigate away from the page.

## Removing ownership

To remove an owner, use the same method you used to add them.

### Removing ownership via YAML

* Update the `x-cortex-owners` block in your YAML to reference only the correct teams or individuals. Ensure that all referenced teams actually exist in Cortex.
* If using [GitOps](/configure/gitops), make sure the YAML is updated and merged to your main branch, then allow Cortex to re-sync. This updates the ownership in the UI to match the YAML.

### Removing ownership via API

Use the [Create or update entity API](/api/readme/catalog-entities#post-api-v1-open-api) to completely replace the entity YAML, or the [Create or patch entity API](/api/readme/catalog-entities#patch-api-v1-open-api) to remove one or more owner and not change the rest of the entity YAML.

### Removing inherited ownership

* Check if the entity is a child of a domain or group with [ownership inheritance](/ingesting-data-into-cortex/entities-overview/entities/ownership/ownership-inheritance) enabled. If so, the parent’s owners may be appended to the entity.
* To remove inherited owners, edit the domain or parent’s owner inheritance setting (e.g. change from `Append` to `None`).


# Defining relationship types

Every organization has structure: teams own services, services depend on each other, domains group related capabilities. Relationship types are how Cortex models that structure, letting you define not just *that* two entities are related, but *how* they relate and *what kinds* of entities can participate.

## Understanding relationship types in Cortex

A relationship type captures the semantics of a connection between entities: its directionality, the roles each side plays, and the constraints on what can appear at either end. Rather than treating all relationships as equivalent links, Cortex distinguishes between a few fundamentally different relationship patterns:

* **Entity relationships** - Customizable relationships (hierarchical or cyclical) between any entity types
* **Team hierarchies** - Hierarchical relationships specifically between teams, including [ownership](/ingesting-data-into-cortex/entities-overview/entities/ownership) over other entities. Learn more in [Understanding hierarchies](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/teams/viewing-teams#understanding-hierarchies).
* **Domain hierarchies** - Hierarchical relationships between domains, with optional inheritance so ownership can flow down from parent to child. Learn more in [Viewing the domain hierarchy](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/domains#viewing-the-domain-hierarchy).
* **Dependencies** - Cyclical relationships between non-team entities. Learn more in [Defining dependencies](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/dependencies).

{% hint style="info" %}
Want to learn more? Check out the Cortex Academy course on [Catalogs, Entities, and Relationships](https://academy.cortex.io/courses/understanding-understanding-catalogs-entities-and-relationships).
{% endhint %}

### **Relationship direction: Source vs. destination**

Every relationship has a direction. The **source** is the parent (the upstream entity), and the **destination** is the child (the downstream entity). For example, in a *Repository* relationship, a `Service` (source/parent) contains a `Repository` (destination/child).

This direction determines how the relationship is drawn in an entity's relationships graph, so define it carefully when creating a relationship type. If upstream and downstream appear reversed, the source and destination entities were likely defined in the opposite order.

### Custom relationship type use cases

<table><thead><tr><th width="162.05206298828125">Relationship type</th><th width="255.739501953125">Description</th><th width="144.203125">Source</th><th>Destination</th></tr></thead><tbody><tr><td><strong>Repository</strong></td><td>Mapping services to repositories to view the hierarchy of repos and the services they contain. For example, a service is linked to its code repository.</td><td>Service</td><td>Repository</td></tr><tr><td><strong>Cloud account to resource</strong></td><td>Associating cloud accounts (like AWS, Google Cloud Project, or Azure subscription) with their respective resources (such as EC2 instances or other cloud resources).</td><td><ul><li>AWS account</li><li>GCP</li><li>Azure subscription</li></ul></td><td><ul><li>AWS resources (e.g., EC2)</li><li>Google Cloud resources</li><li>Azure resources</li></ul></td></tr><tr><td><strong>Service to environment</strong></td><td>Linking services to their deployment environments.</td><td>Service</td><td>Environment</td></tr><tr><td><strong>Monorepo</strong></td><td>Mapping multiple services to a single repository.</td><td>Repository</td><td>Service</td></tr><tr><td><strong>Service to endpoint</strong></td><td>Associating services with their endpoints.</td><td>Service</td><td>Endpoint</td></tr><tr><td><strong>Data center modeling</strong></td><td>Representing data centers and their relationships to other infrastructure components.</td><td>Data center</td><td>Component</td></tr></tbody></table>

{% hint style="warning" %}
Use team [ownership](/ingesting-data-into-cortex/entities-overview/entities/ownership) to represent ownership relationships, not custom relationship types.
{% endhint %}

## Viewing relationship types

### Viewing all configured relationship types

1. From the main sidebar, expand **Catalogs**, then select **All entities**.
2. Select the **Relationship types** tab.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/OOyl3qM4moPcJC0Yop00" alt="The &#x27;Relationship types&#x27; tab on the Entities page." width="375"><figcaption></figcaption></figure></div>
3. Select a relationship type from the list to view more information.

### Viewing relationships on entity pages

If an entity belongs to a relationship, you can explore that context directly from its [entity details page](/ingesting-data-into-cortex/entities-overview/entities/details).

1. Navigate to the entity's details page.
2. From the left entity details sidebar, select **Relationships**. Relationship types associated with the entity appear in the relationships graph.

In the example below, the entity `California` belongs to a relationship called `Geography` . Relationships default to **graph view**, giving you a visual map of parent/child connections, where sources (parents/upstream) connect to their destinations (children/downstream).

<div align="left" data-with-frame="true"><figure><img src="/files/ylRCehi5PuTKkXaF4EPA" alt="The relationship graph of an entity." width="563"><figcaption></figcaption></figure></div>

From the graph, click any entity to view a quick summary of its metadata. Select **Go to entity** to navigate directly to that entity's detail page.

<div align="left" data-with-frame="true"><figure><img src="/files/YEz3oeunR66kxlHX8nuJ" alt="" width="563"><figcaption></figcaption></figure></div>

Select **Table view** to see the same data in a structured list. This view is useful for quickly scanning or sorting related entities.

<div align="left" data-with-frame="true"><figure><img src="/files/yXZCT08HLJ34fQqs0TRv" alt="" width="563"><figcaption></figcaption></figure></div>

## Entity relationship CQL

You can create Scorecard rules and write [CQL queries](/standardize/cql) based on entity relationships. See more examples in the [CQL Explorer](https://app.getcortexapp.com/admin/cql-explorer) in Cortex.

<details>

<summary>Entity relationship destinations</summary>

All recursive destinations an entity for a relationship type, with an optional depth parameter to expand results

**Definition -** `entity.destinations(relationshipType = "my-relationship")`

**Examples**

You could write a Scorecard rule to ensure that an entity has at least one destination with the "my-relationship" type:

```
entity.destinations(relationshipType = "my-relationship").length > 0
```

</details>

<details>

<summary>Entity relationship sources</summary>

All recursive sources an entity for a relationship type, with an optional depth parameter to expand results

**Definition -** `entity.sources(relationshipType = "my-relationship")`

**Examples**

You could write a Scorecard rule that ensures an entity has at least one source with the "my-relationship" type:

```
entity.sources(relationshipType = "my-relationship").length > 0
```

</details>


# Managing relationships

Cortex captures your organization's structure through two complementary concepts: **relationship types** and **relationship connections**.

A **relationship type** defines the rules of a connection: what it means, which entity types can participate, whether it flows in one direction or can form cycles, and whether metadata should inherit across it. Think of it as a template (e.g. "Repository," "Cloud account to resource," or "Service to environment") that describes *how* two kinds of entities relate before any specific entities are linked.

A **relationship connection** is a concrete instance of that template: the actual link between two specific entities. For example, once you've defined a "Repository" relationship type, a connection is what ties your `payments-service` entity to its specific GitHub repository entity.

This separation gives you flexibility and consistency. You define the shape of a relationship once, then apply it across as many entity pairs as needed. Relationships can be hierarchical (acyclical, like an org chart) or graph-like (cyclical, like service dependencies), and they can carry ownership metadata that flows from parent to child.

Together, relationship types and connections give Cortex a way to reflect how your systems actually fit together.

## Creating relationship types

Users with the `Edit Relationships` permission can create a relationship type.

Relationship types must be created via the Cortex UI or the API.

### Creating relationship types via the Cortex UI

1. From the main sidebar, expand **Catalogs**, then select **All entities**.
2. Select the **Relationship types** tab.
3. In the upper-right corner, click **Create**, then click **Create new relationship type**.\
   The **Create new relationship** page is displayed.
4. In the **Details** section, do the following:
   1. Under **Name**, enter a name for the relationship type (required).
   2. The **Identifier** auto-populates based on the relationship type name and is made up of letters, digits, and hyphens.
   3. Under **Description**, enter a description of the relationship to help others understand its purpose.
   4. Toggle on **Create relationship type catalog** to create a catalog for this relationship type.
5. In the **Source entity types** section, do the following:
   1. From the drop-down menu, select an entity type. If no entity type is selected, all entity types are available as sources.
   2. Toggle on **Exclude** to hide all entity types from sources, or leave toggled off to include all.
   3. Optionally, customize the singular and plural wording of the entity types and the cardinality.
6. In the **Destination entity types** section, do the following:
   1. From the drop-down menu, select an entity type. If no entity type is selected, all entity types are available as destinations.
   2. Toggle on **Exclude** to hide all entity types from destinations, or leave toggled off to include all.
   3. Optionally, customize the singular and plural wording of the entity types and the cardinality.
7. In the **Relationship constraints** section, do the following:
   1. Select an architecture:
      1. **Acyclical** - Recommended for hierarchical data such as an org chart or product hierarchy.
      2. **Cyclical** - Recommended for graph-like data such as dependencies.
   2. Under **Definition location**, select a location:
      1. **From destination** - If selected, relationships can only be defined from destination entities.
      2. **From source** - If selected, relationships can only be defined from source entities.
      3. **Either source or destination** - If selected, relationships can be defined by either destination or source entities.
   3. Toggle on **Ownership** to configure inheritance for the relationship type, then select how metadata will be inherited. Learn more in [Ownership inheritance](/ingesting-data-into-cortex/entities-overview/entities/ownership/ownership-inheritance).
      1. **Fallback**: This option uses the source's data only if the destination does not have anything defined.
      2. **Append**: This option appends the source's data to the destination, even if it already has data defined.
8. Click **Create**.

### Creating relationship types via the API

You can create, update, and delete relationship types using the [Cortex API](https://docs.cortex.io/api/readme/entity-relationship-types).

## Creating relationship connections between entities

After creating a relationship type, connections between entities can be made via the Cortex UI, an entity descriptor, the API, or an integration.

### **Creating relationship connections via the UI**

1. Navigate to the [entity's details page](/ingesting-data-into-cortex/entities-overview/entities/details).
2. In the upper-right corner, click **Configure entity**.
3. From the left entity sidebar, click **Relationships**.
4. In the **Relationship type** section, select a relationship type to configure from the drop-down menu.
5. Select the entities you want to connect. The available fields depend on the relationship type selected.
6. Click **Save changes**.

### Creating relationship connections via an entity descriptor

Once a relationship type exists, you can define the connection in either the source or destination entity's YAML using the `x-cortex-relationships` tag.

In the example below, a source entity's YAML has a defined relationship type called `app-components` and has destination entities `production-ui` and `backend-app`.

```yaml
  x-cortex-relationships:
  - type: app-components
    destinations:
    - tag: production-ui
    - tag: backend-app
```

Optionally, this can be configured in the YAML of the destination by replacing `source` with `destination` in the YAML above.

The relationship between entities in Cortex is based on the relationship being defined in the entity's YAML file; Cortex does not set hierarchies or relationships based on a YAML file's location in your repository.

### Creating relationship connections via the API

You can create, update, and delete relationships between entities using the [Cortex API](https://docs.cortex.io/api/readme/entity-relationships).

### Creating relationship connections via an integration

At this time, Cortex only supports integration-based relationship creation via AWS. See [Configuring tag-based auto-linking](/ingesting-data-into-cortex/integrations/aws/importing-entities-from-aws#configuring-tag-based-auto-linking-for-aws) for more information.

## Editing a relationship type

Users with the `Edit Relationships` permission can edit a relationship type.

1. From the main sidebar, expand **Catalogs**, then select **All entities**.
2. Select the **Relationship types** tab.
3. Locate the relationship type you want to edit, then click the **pencil icon** next to it.
4. Make any necessary changes.
5. Click **Save**.

## Deleting a relationship type

Users with the `Edit Relationships` permission can delete a relationship type.

1. From the main sidebar, expand **Catalogs**, then select **All entities**.
2. Select the **Relationship types** tab.
3. Select the relationship type you want to delete.
4. Click the **Overflow menu** icon, then click **Delete relationship type**.


# Grouping entities

Groups are how you slice your catalog. They are free-form tags with no hierarchy or ownership semantics. Apply them to any set of [entities](/ingesting-data-into-cortex/entities-overview/entities) that belong together, and use those labels to filter, report, and scope work across Cortex.

Think of groups as the vocabulary you invent to describe your system. You might use them to express priority (`tier-0`, `tier-1`), stack (`python`, `java`, `kotlin`), architectural role (`backend`, `frontend`, `library`, `api`), or any other dimension that matters to your organization.

Once entities are tagged, groups become a cross-cutting lens: filter a Scorecard to only Python services, build a catalog view of all tier-0 systems, or aggregate production readiness scores by tier.

## What you can do with groups

**Segment entities** - Tag entities with whatever labels make sense for your org. Groups are additive; an entity can belong to any number of groups.

**Filter throughout Cortex** - Use groups as inclusion or exclusion criteria in [Scorecards](/standardize/scorecards), [catalogs](/ingesting-data-into-cortex/catalogs), and [CQL reports](/standardize/cql/cql-reports). For example, apply a security Scorecard only to backend services, or surface a catalog view that shows only tier-0 entities.

**Aggregate and report** - Break down Scorecard results by group. For example, view a Production Readiness Scorecard segmented by tier to see which tier is furthest from your standards.

## Viewing groups on an entity

When you open an [entity's detail page](/ingesting-data-into-cortex/entities-overview/entities/details), its groups are listed in the upper-right corner. Clicking any group name takes you to a list of all other entities that share that tag.

<div align="left" data-with-frame="true"><figure><img src="/files/HgSR3u5AibaXx8Mc1gs2" alt="" width="563"><figcaption></figcaption></figure></div>

## Defining and applying groups

Groups can be created and applied via the Cortex UI, an entity descriptor YAML file, or the API. Each method has distinct behavior.

### Behavior by method

There are important differences in how groups created via different methods interact with each other:

<table><thead><tr><th width="188.1875"></th><th align="center">UI</th><th align="center">Entity descriptor</th><th align="center">API</th></tr></thead><tbody><tr><td>Visible in entity YAML</td><td align="center"><i class="fa-check">:check:</i></td><td align="center"><i class="fa-check">:check:</i></td><td align="center"><i class="fa-xmark">:xmark:</i></td></tr><tr><td>Removable via UI</td><td align="center"><i class="fa-check">:check:</i></td><td align="center"><i class="fa-check">:check:</i></td><td align="center"><i class="fa-xmark">:xmark:</i></td></tr><tr><td>Overwritten by API</td><td align="center"><i class="fa-xmark">:xmark:</i></td><td align="center"><i class="fa-xmark">:xmark:</i></td><td align="center">—</td></tr></tbody></table>

Specifically:

* Groups set in the entity descriptor YAML cannot be overwritten by an API call.
* Groups created via the API do not appear in the entity descriptor YAML.
* Groups created via the API cannot be removed from the Cortex UI.

### Defining and applying groups via the Cortex UI

1. Navigate to the [entity's details page](/ingesting-data-into-cortex/entities-overview/entities/details).
2. In the upper-right corner, click **Configure entity**.
3. Locate the **Details** section.
4. From the **Groups** drop-down menu, select a group or groups to apply to the entity.
   * To create a new group, type the group name into the **Search items** field, then click **Add new \[group name]**. The group is created and applied to the entity.
5. Click **Save changes**.

### Defining and applying groups via an entity descriptor

Define groups as a list under `x-cortex-groups`:

```yaml
x-cortex-groups:
    - tier-0
    - language:kotlin
```

Note that group name may not contain whitespace.

### Defining and applying groups via the API

Use the [Groups API](/api/readme/groups) to add groups to an entity programmatically.

## Troubleshooting and FAQ

**When should I use groups instead of** **custom data?**

Groups work best for categorical, enumerable labels, e.g. `backend` vs. `frontend` or `tier-0` vs. `tier-1`. If you need freeform or structured metadata (e.g. `availability-zones`: \[`east`, `west`]), use [custom data](/ingesting-data-into-cortex/entities-overview/entities/custom-data) instead.

**What is the difference between `x-cortex-service-groups` and `x-cortex-groups`?**

There is no functional difference. `x-cortex-service-groups` is deprecated in favor of `x-cortex-groups`, but the change is backward-compatible; existing configurations using the old key will continue to work.


# Adding external documentation

Documentation lives in too many places—wikis, git repos, API spec tools, dashboards. Cortex pulls it together on the entity that owns it, so the people working with a service don't have to go looking.

You can attach four kinds of documentation to an entity:

* **Links** - Any URL—e.g. runbooks, tech specs, dashboards, health checks—or custom types you define
* **Git-driven markdown** - Markdown files from your repo, embedded automatically
* **API specs** - OpenAPI/Swagger or AsyncAPI specs, rendered in a built-in API explorer
* **Dashboard charts** - Embedded charts from Datadog, Grafana, New Relic, or other sources

Attached documentation appears in the **Links & docs** section of an [entity's details page](/ingesting-data-into-cortex/entities-overview/entities/details):

<div align="left" data-with-frame="true"><figure><img src="/files/XLPMelH44B0sQpmkATOD" alt="" width="563"><figcaption></figcaption></figure></div>

## Adding links to an entity

### Adding links via the Cortex UI

#### Prerequisites

Before editing an entity via the UI, make sure that UI editing is enabled.

1. Navigate to the [entity's details page](/ingesting-data-into-cortex/entities-overview/entities/details).
2. In the upper-right corner, click **Configure entity**.
3. In the entity's left sidebar, click **Links**.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/a5Ql62MOs0aEt5WlKeTI" alt="The Links page in the Cortex UI." width="375"><figcaption></figcaption></figure></div>
4. Click **+Add**.
5. In the **Link** side panel, do the following:
   * From the **Type** drop-down menu, select the type of link.
     * To create a new type of link, enter the name into the **Search items** field, then click **Add new \[link type name]**. The link type is created and applied to the entity.
   * Under **Name**, enter a name for the link.
   * Under **URL**, enter the URL.
   * Under **Description**, enter a description of the link.
6. Click **Add**.

### Adding links via an entity descriptor

In the entity descriptor, add a list of `link` objects:

```yaml
x-cortex-link:
  - name: Checkout Service Runbook
    type: runbook
    url: https://wiki.example.com/runbooks/checkout-service
    description: Steps for diagnosing and resolving incidents in the checkout service

```

`name`, `type`, and `url` are required. The `type` value is freeform. Common examples include `dashboard`, `documentation`, `healthcheck`, `logs`, `metrics`, and `runbook`.

## Adding git-driven Markdown docs to an entity

Cortex automatically detects and embeds markdown files from the `docs` folder of your linked repository, or from the root directory. When relevant files are found, they appear under **Links & docs** in the entity's left sidebar. Markdown is rendered using the [React markdown library](https://github.com/remarkjs/react-markdown).

No configuration is required as this happens automatically when a repository is associated with the entity.

## Adding API specs to an entity

Cortex renders OpenAPI/Swagger and AsyncAPI specs in a built-in API explorer on the [entity details page](/ingesting-data-into-cortex/entities-overview/entities/details). From the API explorer, you can also authorize your API and run queries directly.

**To access the API explorer**:

1. Navigate to the [entity's details page](/ingesting-data-into-cortex/entities-overview/entities/details).
2. In the left entity sidebar, click **API explorer**.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/fvrIoG7UYWenk6u00ZEZ" alt="The API Explorer in Cortex." width="375"><figcaption></figcaption></figure></div>

### Adding OpenAPI docs

#### From an external URL

Add the spec URL to the entity descriptor with type `OPENAPI` :

```yaml
x-cortex-link:
  - name: Payment Service API Spec
    type: OPENAPI
    url: https://api.example.com/specs/payment-service.yaml
```

#### **From your git repo (relative path)**

```yaml
x-cortex-link:
  - name: Payment Service API Spec
    type: OPENAPI
    url: ./docs/payment-service-spec.yaml
```

#### **From another git repo**

You can reference specs in repos not associated with the entity, using the format `provider:org/repo:path/to/file`. To target a specific branch, use `provider:org/repo:branch:path/to/file`. If branch is omitted, the repo's default branch is used.

```yaml
# GitHub
x-cortex-link:
  - name: Payment Service API Spec
    type: OPENAPI
    url: github:acme-corp/api-specs:services/payment-service/openapi.yaml

# GitLab
  - name: Payment Service API Spec
    type: OPENAPI
    url: gitlab:acme-corp/api-specs:services/payment-service/openapi.yaml

# Azure DevOps
  - name: Payment Service API Spec
    type: OPENAPI
    url: azuredevops:acme-corp/api-specs:services/payment-service/openapi.yaml

# Bitbucket
  - name: Payment Service API Spec
    type: OPENAPI
    url: bitbucket:acme-corp/api-specs:services/payment-service/openapi.yaml

```

#### Via the Cortex API

Send your OpenAPI JSON or YAML to the endpoint `POST /api/v1/catalog/documentation/openapi`, using your entity's [Cortex tag](/ingesting-data-into-cortex/entities-overview/entities#cortex-tag). One API doc per entity can be uploaded. It will appear automatically as an API doc entry in the API explorer dropdown.

The request body is JSON with a single field:

<table><thead><tr><th width="90.5546875">Field</th><th width="101.16796875">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>spec</code></td><td>string</td><td>The OpenAPI JSON or YAML as a string</td></tr></tbody></table>

To convert a YAML or JSON file to a string, you can use `jq`:

```shellscript
$(cat my_file.yaml | jq -Rsa)
```

See the [API docs](/api/readme/docs) for authentication details.

### Adding AsyncAPI docs

Add AsyncAPI specs from an external URL or a path within your git repository, using type `ASYNC_API`:

```yaml
x-cortex-link:
  - name: Order Events API Spec
    type: ASYNC_API
    url: ./docs/order-events-spec.yml
```

## Adding embedded dashboards to an entity

Cortex supports embedding individual charts from Datadog, Grafana, New Relic, or any other source that provides an iframe embed URL. Embedded charts appear on the Dashboard page in the entity's left sidebar.

```yaml
x-cortex-dashboards:
  embeds:
    - type: datadog
      url: https://app.datadoghq.com/graph/embed?token=abc123&height=300&width=600
```

* `type` is optional. Accepted values are `datadog`, `grafana`, and `newrelic`.
  * Content from sources other than Datadog, Grafana, or New Relic is supported. Omit the `type` field, and ensure the URL is publicly accessible or supports cross-platform authentication. For example, content accessible via VPN displays in Cortex when you're on the VPN.
* `url` is the `src` value from the iframe embed generated by your dashboard tool, not the dashboard's browser URL.
* The URL must be publicly accessible, or accessible via the same VPN your browser is on.

{% hint style="info" %}
You can embed individual charts only, not full dashboards. If you're using Grafana and seeing embed errors, verify that [embedding is enabled](https://grafana.com/docs/grafana/latest/administration/configuration/#allow_embedding) in your Grafana instance.
{% endhint %}

## Accessing docs via Slack

If you have the Slack integration configured, you can look up an entity's documentation links without leaving Slack. Mention `@Cortex` in a channel or direct message and ask a question like "Where are the docs for payments-api?".

For setup and usage details, refer to [Using the AI assistant](/ingesting-data-into-cortex/integrations/slack/using-the-integration-for-slack-ai-assistant#using-the-ai-assistant).&#x20;


# Adding deployment data via API

Getting deployment data into Cortex is critically important for both engineering insights and organizational success. It enables the use of [Eng Intelligence](/improve/eng-intelligence) to assess [DORA metrics](/improve/eng-intelligence/dashboards/dora-dashboard) and other KPIs to understand how quickly and efficiently your teams are shipping code. Deployment data also gives you the insight needed to create [Scorecards](/standardize/scorecards) and [Initiatives](/improve/initiatives) that promote process improvement across teams.

## Adding deployment data to Cortex

To get deployment data into Cortex, you must use the [Add deployment for entity](/api/readme/deploys) API endpoint.

### Deploy data pipeline examples

In these examples, the repository secret or variable contains a valid [Cortex API key](/configure/settings/api-keys), and the repository name matches the [Cortex tag](/ingesting-data-into-cortex/entities-overview/entities#cortex-tag).

<details>

<summary>GitHub Action</summary>

In this example, a repository secret called `CORTEX_TOKEN` contains a valid Cortex API key.

```yaml
name: Build and Deploy with Status Updates

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]

env:
  CORTEX_API_URL: "https://api.getcortexapp.com/api/v1/catalog"
  PROJECT_NAME: "my-application"

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    
    steps:
    - name: Checkout code
      uses: actions/checkout@v4
    
    - name: Validate Cortex token
      run: |
        if [ -z "${{ secrets.CORTEX_TOKEN }}" ]; then
          echo "ERROR: CORTEX_TOKEN secret not configured"
          exit 1
        fi
    
    - name: Setup Node.js
      uses: actions/setup-node@v4
      with:
        node-version: '18'
        cache: 'npm'
    
    - name: Install dependencies
      run: npm ci
      
    - name: Run tests
      run: npm test
      
    - name: Build application
      run: npm run build
      
    - name: Deploy to staging
      run: |
        echo "Deploying to staging environment..."
        # Your deployment commands here
        # This might fail intentionally for demonstration

  # Guaranteed notification job that runs regardless of build-and-deploy outcome
  notify-result:
    runs-on: ubuntu-latest
    needs: build-and-deploy
    if: always() # This ensures the job runs regardless of build-and-deploy outcome
    
    steps:
    - name: Send deployment notification to Cortex
      run: |
        echo "Previous job result: ${{ needs.build-and-deploy.result }}"
        REPO_NAME=$(echo "${{ github.event.repository.name }}" | tr '[:upper:]' '[:lower:]')
        echo "Using repo name: $REPO_NAME"
        
        # Check the status of the previous job
        if [ "${{ needs.build-and-deploy.result }}" == "success" ]; then
          TYPE="DEPLOY"
          STATUS="success"
          MESSAGE="All jobs completed successfully"
        elif [ "${{ needs.build-and-deploy.result }}" == "failure" ]; then
          TYPE="ROLLBACK"
          STATUS="failed"
          MESSAGE="Build and deploy job failed"
        elif [ "${{ needs.build-and-deploy.result }}" == "cancelled" ]; then
          TYPE="ROLLBACK"
          STATUS="cancelled"
          MESSAGE="Build and deploy job was cancelled"
        else
          TYPE="ROLLBACK"
          STATUS="skipped"
          MESSAGE="Build and deploy job was skipped"
        fi
        
        curl -L \
          --request POST \
          --max-time 30 \
          --retry 2 \
          --url "${{ env.CORTEX_API_URL }}/$REPO_NAME/deploys" \
          --header "Authorization: Bearer ${{ secrets.CORTEX_TOKEN }}" \
          --header "Content-Type: application/json" \
          --data "{
            \"customData\": {
              \"workflow\": \"${{ github.workflow }}\",
              \"run_id\": \"${{ github.run_id }}\",
              \"branch\": \"${{ github.ref_name }}\",
              \"final_status\": \"$STATUS\",
              \"message\": \"$MESSAGE\",
              \"actor\": \"${{ github.actor }}\",
              \"repository\": \"${{ github.repository }}\"
            },
            \"deployer\": {
              \"email\": \"${{ github.actor }}@users.noreply.github.com\",
              \"name\": \"${{ github.actor }}\"
            },
            \"environment\": \"staging\",
            \"sha\": \"${{ github.sha }}\",
            \"timestamp\": \"$(date -u +"%Y-%m-%dT%H:%M:%SZ")\",
            \"title\": \"Final deployment $STATUS - ${{ github.workflow }}\",
            \"type\": \"$TYPE\",
            \"url\": \"${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\"
          }"
```

</details>

<details>

<summary>GitLab pipeline</summary>

**Prerequisites**

Before running this pipeline, define a CI/CD variable in GitLab that stores the Cortex API key. Confirm the repository contains a `package.json` file.

**Failure behavior**

If any stage fails, the entire pipeline fails and a `ROLLBACK` event sends to Cortex.

```yaml
stages:
  - build
  - test
  - deploy
  - notify

variables:
  CORTEX_API_URL: "https://api.getcortexapp.com/api/v1/catalog"

# Global settings
image: node:18

build_job:
  stage: build
  script:
    - echo "Building application..."
    - npm ci
    - npm run build
  artifacts:
    paths:
      - dist/
    expire_in: 1 hour

test_job:
  stage: test
  script:
    - echo "Running tests..."
    - npm test
  dependencies:
    - build_job

deploy_job:
  stage: deploy
  script:
    - echo "Deploying to staging..."
    # Your deployment commands here
    - sleep 2
    - echo "Deployment completed"
  dependencies:
    - build_job
  environment:
    name: staging

# This job always runs and reports pipeline status to Cortex
notify_cortex:
  stage: notify
  image: curlimages/curl:latest
  before_script:
    # Check if previous stages succeeded by examining needs
    - |
      if [ "$BUILD_JOB_STATUS" = "success" ] && [ "$TEST_JOB_STATUS" = "success" ] && [ "$DEPLOY_JOB_STATUS" = "success" ]; then
        PIPELINE_STATUS="success"
        DEPLOY_TYPE="DEPLOY"
        MESSAGE="Pipeline completed successfully"
      else
        PIPELINE_STATUS="failed"
        DEPLOY_TYPE="ROLLBACK"
        MESSAGE="Pipeline failed - one or more stages failed"
      fi
      
      echo "Pipeline Status: $PIPELINE_STATUS"
      echo "Deploy Type: $DEPLOY_TYPE"
      echo "Message: $MESSAGE"
  script:
    - |
      # Convert repo name to lowercase
      REPO_NAME=$(echo "$CI_PROJECT_NAME" | tr '[:upper:]' '[:lower:]')
      echo "Repository: $REPO_NAME"
      
      # Get current timestamp
      TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
      
      # Send notification to Cortex
      curl -L \
        --request POST \
        --max-time 30 \
        --retry 2 \
        --url "$CORTEX_API_URL/$REPO_NAME/deploys" \
        --header "Authorization: Bearer $CORTEX_TOKEN" \
        --header "Content-Type: application/json" \
        --data "{
          \"customData\": {
            \"pipeline_id\": \"$CI_PIPELINE_ID\",
            \"job_id\": \"$CI_JOB_ID\",
            \"branch\": \"$CI_COMMIT_REF_NAME\",
            \"pipeline_status\": \"$PIPELINE_STATUS\",
            \"message\": \"$MESSAGE\",
            \"pipeline_url\": \"$CI_PIPELINE_URL\",
            \"project_path\": \"$CI_PROJECT_PATH\"
          },
          \"deployer\": {
            \"email\": \"$GITLAB_USER_EMAIL\",
            \"name\": \"$GITLAB_USER_NAME\"
          },
          \"environment\": \"staging\",
          \"sha\": \"$CI_COMMIT_SHA\",
          \"timestamp\": \"$TIMESTAMP\",
          \"title\": \"Pipeline $PIPELINE_STATUS - $CI_PROJECT_NAME\",
          \"type\": \"$DEPLOY_TYPE\",
          \"url\": \"$CI_PIPELINE_URL\"
        }"
      
      if [ $? -eq 0 ]; then
        echo "Successfully notified Cortex"
      else
        echo "Failed to notify Cortex, but continuing..."
      fi
  needs:
    - job: build_job
      artifacts: false
    - job: test_job  
      artifacts: false
    - job: deploy_job
      artifacts: false
  when: always
```

</details>

<details>

<summary>Azure DevOps</summary>

In this example, a variable called `CORTEX_TOKEN` contains a valid Cortex API key.

```yaml
trigger:
  branches:
    include:
      - main
      - develop

pr:
  branches:
    include:
      - main

variables:
  CORTEX_API_URL: 'https://api.getcortexapp.com/api/v1/catalog'

pool:
  vmImage: 'ubuntu-latest'

stages:
- stage: Build
  displayName: 'Build Stage'
  jobs:
  - job: BuildJob
    displayName: 'Build Application'
    steps:
    - task: NodeTool@0
      inputs:
        versionSpec: '18.x'
      displayName: 'Install Node.js'

    - script: |
        echo "Building application..."
        npm ci
        npm run build
      displayName: 'Build Application'

    - publish: dist
      artifact: BuildArtifacts
      displayName: 'Publish Build Artifacts'

- stage: Test
  displayName: 'Test Stage'
  dependsOn: Build
  jobs:
  - job: TestJob
    displayName: 'Run Tests'
    steps:
    - task: NodeTool@0
      inputs:
        versionSpec: '18.x'
      displayName: 'Install Node.js'

    - script: |
        echo "Running tests..."
        npm ci
        npm test
      displayName: 'Run Tests'

- stage: Deploy
  displayName: 'Deploy Stage'
  dependsOn: Test
  jobs:
  - job: DeployJob
    displayName: 'Deploy to Staging'
    steps:
    - script: |
        echo "Deploying to staging..."
        sleep 2
        echo "Deployment completed"
      displayName: 'Deploy Application'

- stage: Notify
  displayName: 'Notify Cortex'
  dependsOn: 
    - Build
    - Test
    - Deploy
  condition: always()
  jobs:
  - job: NotifyJob
    displayName: 'Send Cortex Notification'
    steps:
    - checkout: none
    
    - bash: |
        echo "Build Stage Result: $(stageDependencies.Build.BuildJob.result)"
        echo "Test Stage Result: $(stageDependencies.Test.TestJob.result)"
        echo "Deploy Stage Result: $(stageDependencies.Deploy.DeployJob.result)"
        
        # Determine overall pipeline status
        BUILD_RESULT="$(stageDependencies.Build.BuildJob.result)"
        TEST_RESULT="$(stageDependencies.Test.TestJob.result)"
        DEPLOY_RESULT="$(stageDependencies.Deploy.DeployJob.result)"
        
        if [ "$BUILD_RESULT" = "Succeeded" ] && [ "$TEST_RESULT" = "Succeeded" ] && [ "$DEPLOY_RESULT" = "Succeeded" ]; then
          PIPELINE_STATUS="success"
          DEPLOY_TYPE="DEPLOY"
          MESSAGE="Pipeline completed successfully"
        else
          PIPELINE_STATUS="failed"
          DEPLOY_TYPE="ROLLBACK"
          MESSAGE="Pipeline failed - one or more stages failed (Build: $BUILD_RESULT, Test: $TEST_RESULT, Deploy: $DEPLOY_RESULT)"
        fi
        
        echo "Pipeline Status: $PIPELINE_STATUS"
        echo "Deploy Type: $DEPLOY_TYPE"
        echo "Message: $MESSAGE"
        
        # Convert repo name to lowercase (extract from full repository name)
        REPO_NAME=$(echo "$(Build.Repository.Name)" | cut -d'/' -f2 | tr '[:upper:]' '[:lower:]')
        echo "Repository: $REPO_NAME"
        
        # Get current timestamp
        TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
        
        # Get deployer information
        DEPLOYER_EMAIL="${BUILD_REQUESTEDFOREMAIL:-devops@company.com}"
        DEPLOYER_NAME="${BUILD_REQUESTEDFOR:-Azure DevOps}"
        
        # Send notification to Cortex
        curl -L \
          --request POST \
          --max-time 30 \
          --retry 2 \
          --url "$(CORTEX_API_URL)/$REPO_NAME/deploys" \
          --header "Authorization: Bearer $(CORTEX_TOKEN)" \
          --header "Content-Type: application/json" \
          --data "{
            \"customData\": {
              \"pipeline_id\": \"$(Build.BuildId)\",
              \"build_number\": \"$(Build.BuildNumber)\",
              \"branch\": \"$(Build.SourceBranchName)\",
              \"pipeline_status\": \"$PIPELINE_STATUS\",
              \"message\": \"$MESSAGE\",
              \"build_url\": \"$(System.TeamFoundationCollectionUri)$(System.TeamProject)/_build/results?buildId=$(Build.BuildId)\",
              \"project\": \"$(System.TeamProject)\",
              \"repository\": \"$(Build.Repository.Name)\"
            },
            \"deployer\": {
              \"email\": \"$DEPLOYER_EMAIL\",
              \"name\": \"$DEPLOYER_NAME\"
            },
            \"environment\": \"staging\",
            \"sha\": \"$(Build.SourceVersion)\",
            \"timestamp\": \"$TIMESTAMP\",
            \"title\": \"Pipeline $PIPELINE_STATUS - $(Build.Repository.Name)\",
            \"type\": \"$DEPLOY_TYPE\",
            \"url\": \"$(System.TeamFoundationCollectionUri)$(System.TeamProject)/_build/results?buildId=$(Build.BuildId)\"
          }"
        
        if [ $? -eq 0 ]; then
          echo "Successfully notified Cortex"
        else
          echo "Failed to notify Cortex, but continuing..."
        fi
      displayName: 'Send Cortex Notification'
      env:
        CORTEX_TOKEN: $(CORTEX_TOKEN)
```

</details>

<details>

<summary>Jenkins</summary>

In this example, the Jenkins job is assumed to be associated with a repository, and the repository name is used to match the Cortex entity tag. The job also assumes a Global Credential named `CORTEX_TOKEN` has been defined, containing a valid Cortex API key.

```yaml
pipeline {
    agent any
    
    environment {
        CORTEX_API_URL = "https://api.getcortexapp.com/api/v1/catalog"
    }
    
    stages {
        stage('Build') {
            steps {
                script {
                    echo "Building application..."
                }
                sh '''
                    node --version
                    npm --version
                    npm ci
                    npm run build
                '''
            }
            post {
                success {
                    script {
                        env.BUILD_STAGE_RESULT = 'SUCCESS'
                    }
                }
                failure {
                    script {
                        env.BUILD_STAGE_RESULT = 'FAILURE'
                    }
                }
            }
        }
        
        stage('Test') {
            steps {
                script {
                    echo "Running tests..."
                }
                sh 'npm test'
            }
            post {
                success {
                    script {
                        env.TEST_STAGE_RESULT = 'SUCCESS'
                    }
                }
                failure {
                    script {
                        env.TEST_STAGE_RESULT = 'FAILURE'
                    }
                }
            }
        }
        
        stage('Deploy') {
            steps {
                script {
                    echo "Deploying to staging..."
                    sh '''
                        sleep 2
                        echo "Deployment completed"
                    '''
                }
            }
            post {
                success {
                    script {
                        env.DEPLOY_STAGE_RESULT = 'SUCCESS'
                    }
                }
                failure {
                    script {
                        env.DEPLOY_STAGE_RESULT = 'FAILURE'
                    }
                }
            }
        }
    }
    
    post {
        always {
            script {
                notifyCortex()
            }
        }
    }
}

def notifyCortex() {
    try {
        echo "Build Stage Result: ${env.BUILD_STAGE_RESULT ?: 'SKIPPED'}"
        echo "Test Stage Result: ${env.TEST_STAGE_RESULT ?: 'SKIPPED'}"
        echo "Deploy Stage Result: ${env.DEPLOY_STAGE_RESULT ?: 'SKIPPED'}"
        
        // Determine overall pipeline status
        def buildResult = env.BUILD_STAGE_RESULT ?: 'SKIPPED'
        def testResult = env.TEST_STAGE_RESULT ?: 'SKIPPED'
        def deployResult = env.DEPLOY_STAGE_RESULT ?: 'SKIPPED'
        
        def pipelineStatus
        def deployType
        def message
        
        if (buildResult == 'SUCCESS' && testResult == 'SUCCESS' && deployResult == 'SUCCESS') {
            pipelineStatus = 'success'
            deployType = 'DEPLOY'
            message = 'Pipeline completed successfully'
        } else {
            pipelineStatus = 'failed'
            deployType = 'ROLLBACK'
            message = "Pipeline failed - one or more stages failed (Build: ${buildResult}, Test: ${testResult}, Deploy: ${deployResult})"
        }
        
        echo "Pipeline Status: ${pipelineStatus}"
        echo "Deploy Type: ${deployType}"
        echo "Message: ${message}"
        
        // Convert repo name to lowercase (extract from job name)
        def repoName = env.JOB_NAME.tokenize('/')[0].toLowerCase()
        echo "Repository: ${repoName}"
        
        // Get Git commit SHA and branch
        def gitCommit = sh(
            script: 'git rev-parse HEAD',
            returnStdout: true
        ).trim()
        
        def gitBranch = sh(
            script: 'git rev-parse --abbrev-ref HEAD',
            returnStdout: true
        ).trim()
        
        // Get current timestamp
        def timestamp = sh(
            script: 'date -u +"%Y-%m-%dT%H:%M:%SZ"',
            returnStdout: true
        ).trim()
        
        // Escape JSON special characters in message
        def escapedMessage = message.replaceAll('"', '\\\\"').replaceAll("'", "\\\\'")
        
        // Get deployer information
        def deployerEmail = env.BUILD_USER_EMAIL ?: 'jenkins@company.com'
        def deployerName = env.BUILD_USER ?: 'Jenkins'
        
        // Build JSON payload
        def jsonPayload = """
        {
            "customData": {
                "pipeline": "${env.JOB_NAME}",
                "build_number": "${env.BUILD_NUMBER}",
                "branch": "${gitBranch}",
                "pipeline_status": "${pipelineStatus}",
                "message": "${escapedMessage}",
                "build_url": "${env.BUILD_URL}",
                "jenkins_url": "${env.JENKINS_URL}"
            },
            "deployer": {
                "email": "${deployerEmail}",
                "name": "${deployerName}"
            },
            "environment": "staging",
            "sha": "${gitCommit}",
            "timestamp": "${timestamp}",
            "title": "Pipeline ${pipelineStatus} - ${env.JOB_NAME}",
            "type": "${deployType}",
            "url": "${env.BUILD_URL}"
        }
        """
        
        // Send notification to Cortex
        withCredentials([string(credentialsId: 'CORTEX_TOKEN', variable: 'CORTEX_TOKEN')]) {
            def curlResult = sh(
                script: """
                    curl -L \\
                      --request POST \\
                      --max-time 30 \\
                      --retry 2 \\
                      --url "${env.CORTEX_API_URL}/${repoName}/deploys" \\
                      --header "Authorization: Bearer \${CORTEX_TOKEN}" \\
                      --header "Content-Type: application/json" \\
                      --data '${jsonPayload}' \\
                      --write-out "%{http_code}" \\
                      --silent \\
                      --output /dev/null
                """,
                returnStdout: true
            ).trim()
            
            if (curlResult == '200' || curlResult == '201') {
                echo "Successfully notified Cortex (HTTP ${curlResult})"
            } else {
                echo "Failed to notify Cortex (HTTP ${curlResult}), but continuing..."
            }
        }
        
    } catch (Exception e) {
        echo "Failed to send Cortex notification: ${e.getMessage()}"
        // Don't fail the build if notification fails
    }
}
```

</details>

### Adding custom data to deployments

Adding a `customData` object to the API call gives you the flexibility to attach metadata that matters to your organization, e.g. build numbers, commit messages, approval info, environment tags, or anything else worth tracking alongside a deploy.&#x20;

If custom data is included with a deployment, it appears on the [entity's details page](/ingesting-data-into-cortex/entities-overview/entities/details) under **CI/CD > Deploys**.&#x20;

**To view deployment custom data**:

1. From the main sidebar, expand **Catalogs**, then select **All entities**.
2. Do one of the following:
   * Select the **All** tab to search and filter across all of your organization's entities.
   * Select the **Mine** tab to search and filter only the entities you own.
   * Note that Cortex saves your selection and restores it the next time you open this page.
3. Select the entity.
4. From the left entity details sidebar, locate the **Connections** section, expand **CI/CD**, then click **Deploys**.
5. Click **Details** next to the relevant deployment entry to expand it and view the custom data.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/9hmXDOcJXE7KEMek1NNH" alt="The &#x27;Details&#x27; button on the Deploys page of an entity."><figcaption></figcaption></figure></div>

## Viewing deployment data

Deployment data is found in the following areas of Cortex:

* [Entity pages](#viewing-deployments-on-entity-pages)
* [Eng Intelligence](#viewing-deployments-in-eng-intelligence)
* [CQL and Scorecards](#use-deployment-data-in-cql-and-scorecards)

### Viewing deployments on entity pages

While viewing an entity's page, you can see its latest deployment information.

To access an entity's page, expand **Catalogs** from the main sidebar, then click **All entities**. Select the entity you want to view.

Deployment information appears in the following areas:

Near the top of the page:

<div align="left" data-with-frame="true"><figure><img src="/files/92m9K1KJDrKLbjpzcHWJ" alt="Deployment information is listed at the top of an entity&#x27;s page." width="375"><figcaption></figcaption></figure></div>

Near the bottom of the page under **Latest events**:

<div align="left" data-with-frame="true"><figure><img src="/files/vzC64el11mIHs4TgkuZp" alt="The &#x27;Latest events&#x27; section of an entity&#x27; page." width="375"><figcaption></figcaption></figure></div>

On the **Events** tab:

<div align="left" data-with-frame="true"><figure><img src="/files/AVwSg4R53T3FyYXs5EkF" alt="The &#x27;Events&#x27; tab selected, showing a visual chart of deploys and all recent entity events." width="375"><figcaption></figcaption></figure></div>

The **Events** page includes:

* A visual chart of deploys
  * By default, the chart shows data from the last month. Click **Last month** in the upper-right to change the timeframe.
* All recent events for the entity
  * Click **Filter** In the upper-right corner of the events list to filter events by type (including **deploys**) and date range.
  * Click **Display** in the upper-right corner of the events list to show dependency events.

<div align="left" data-with-frame="true"><figure><img src="/files/mVGkv83Mk1MNamTxqqRQ" alt="The &#x27;Display&#x27; and &#x27;Filter&#x27; options in the events list." width="375"><figcaption></figcaption></figure></div>

### Viewing deployments in Eng Intelligence

When you add deployment data to Cortex, that data feeds into [Eng Intelligence](/improve/eng-intelligence) reporting, giving you visibility into [deploy metrics](/improve/eng-intelligence/eng-intelligence#metrics) such as average deploys per week and change failure rate.

**To view deploy metrics in Eng Intelligence**:

1. From the main sidebar, expand **Eng Intelligence**, then select **All metrics**.&#x20;
2. In the upper-left corner, click the drop-down to change the entity type, e.g. domain.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/ddD2kKUHYEQObhUjpit4" alt="The drop-down menu, located in the upper-left corner of the page." width="375"><figcaption></figcaption></figure></div>
3. Locate the entity whose deploy metrics you want to view, then click into the **Avg deploys/week** and **Deploy change failure rate** columns to get more information including trends and related activity. <br>

   <div align="left" data-with-frame="true"><figure><img src="/files/fpYzZBQgZRxzyFcRA4NM" alt="The &#x27;Avg deploys/week&#x27; and &#x27;Deploy change failure rate&#x27; columns." width="375"><figcaption></figcaption></figure></div>

For more information, including how to filter the page view, see [All metrics](/improve/eng-intelligence/eng-intelligence).

### Using deployment data in CQL and Scorecards

You can use deploy data to write rules for [Scorecards](/standardize/scorecards) and to create [CQL reports](/standardize/cql/cql-reports).

#### CQL reference

Deploys are added to an entity through the [public API](/api/readme/deploys).

**Definition** -  `deploys(lookback: Duration, types: List): List`

**Example**

In a Scorecard, you can write a rule to check whether an entity had fewer than 5 bug fixes in the last month:

```
deploys(lookback = duration("P1M"), types = ["DEPLOY"]).filter((deploy) => deploy.customData != null AND deploy.customData.get("bugFix") == true).length = 2
```

Write a rule to verify that there was, on average, less than 1 rollback for every 4 deploys in the past month:

```
deploys(lookback=duration("P1M"),types=["ROLLBACK"]).length / deploys(lookback=duration("P1M"),types=["DEPLOY", "ROLLBACK", "RESTART"]).length < 0.25
```


# Adding custom data

Custom data extends Cortex's out-of-the-box metadata by letting you attach additional attributes to entities. It can be used in CQL queries and Scorecard rules.

Custom data can be defined manually in [the entity descriptor](#defining-custom-data-in-the-entity-descriptor), added programmatically [via API](#defining-custom-data-via-api), or sent through a [custom webhook integration](#defining-custom-data-via-webhook).

## Custom data vs. custom metrics

Cortex also offers [custom metrics for Eng Intelligence](/improve/eng-intelligence/custom-metrics). Note the following differences between custom data and custom metrics:

* **Custom data** - Used for static or slowly changing metadata (e.g. deployment environments, compliance statuses). Best for enriching entity details, reporting, and Scorecard rules. Note that new values overwrite previous ones for the same key, so it's not suited for time-sensitive tracking. Refer to the [use cases](#use-cases) below.
* **Custom metrics** - Used for time series or trending data (e.g. incident counts, SLOs). Designed for analytics; use them in dashboards, entity pages, and Scorecards. See [Custom metrics](/improve/eng-intelligence/custom-metrics) for more information.

## Defining custom data

There are a few ways to add custom data to an entity:

* **In the entity descriptor** - Best for low-volume, human-maintained data; requires updating the entity's YAML when the data changes.
* **Via REST API** (`POST`) - Best for data from automated processes like CI/CD pipelines.
* **Via webhook** - Useful when you don't have access to the [Cortex tag](/ingesting-data-into-cortex/entities-overview/entities#cortex-tag) or can't add authentication headers, as it requires neither.

### Defining custom data in the entity descriptor

{% hint style="info" %}
Learn more about [entity YAML descriptors](/ingesting-data-into-cortex/entities-overview/entities#defining-entities-via-yaml-file) in the Managing entities documentation.
{% endhint %}

The simplest way to add custom data is to define an object under `x-cortex-custom-metadata`:

```yaml
x-cortex-custom-metadata:
  team-owner: platform-engineering
  deployment-env: production
  compliance-status:
    value: SOC2
    description: Certified under SOC2 Type II as of 2024.
  pagerduty-enabled: true
```

<table><thead><tr><th width="79.8203125">Field</th><th width="424.35546875">Description</th><th align="center">Required</th></tr></thead><tbody><tr><td><code>key</code></td><td>Key or title for the custom data. Anything defined <strong>before</strong> the <code>:</code> serves as the <code>key</code>.</td><td align="center"><strong>✓</strong></td></tr><tr><td><code>value</code></td><td>Value for the custom data. Anything defined <strong>after</strong> the <code>:</code> is the <code>value</code>.</td><td align="center"><strong>✓</strong></td></tr></tbody></table>

Custom data supports any type: scalars (strings, numbers, booleans), objects, and lists. Once added, key-value pairs appear on the entity's custom data page, tagged as YAML.

#### **Adding descriptions**

To include a description alongside a value, use the explicit `value` + `description` syntax. Note that when a description is present, `value` must be explicitly defined (rather than inlined):

```yaml
x-cortex-custom-metadata:
  supported-regions:
    value: 3
    description: us-east-1, eu-west-1, ap-southeast-1
  on-call-rotations:
    value: 2
    description: Primary and secondary on-call rotations are active for this service.
```

<table><thead><tr><th width="128.27734375">Field</th><th width="379.828125">Description</th><th align="center">Required</th></tr></thead><tbody><tr><td><code>key</code></td><td>Key or title for the custom data. Anything defined <strong>before</strong> the <code>:</code> serves as the <code>key</code>.</td><td align="center"><strong>✓</strong></td></tr><tr><td><code>value</code></td><td>Value for the key; should be defined explicitly with <code>value:</code>.</td><td align="center"><strong>✓</strong></td></tr><tr><td><code>description</code></td><td>Description of the custom data</td><td align="center"><strong>✓</strong></td></tr></tbody></table>

{% hint style="info" %}
Descriptions are always optional, but if you want to add one, the `value` key is required.
{% endhint %}

### Defining custom data via API

You can pipe custom data directly into Cortex by POSTing to `/api/v1/catalog/{tag}/custom-data`, where `{tag}` is the entity's `x-cortex-tag`. The request body requires JSON. See the [Custom data API docs](/api/readme/custom-data) for authentication details and required fields.

**Key precedence and overwriting**

If a key is already defined in the entity descriptor, the API does not overwrite it. Instead, it returns the existing value with `YAML` as the source. To explicitly overwrite a YAML-defined value, use the `force=true` query parameter. That said, if you find yourself relying on `force=true`, it's worth updating or removing the field from the YAML to keep a clear source of truth.

{% hint style="info" %}
Custom data added via API displays with an API tag.
{% endhint %}

**Bulk upload**

To upload multiple keys for one or more entities at once, `PUT` to `/api/v1/catalog/custom-data`:

```json
{
  "values": {
    "payments-service": [
      {
        "key": "deployment-env",
        "value": "production",
        "description": "The environment this service is currently deployed to."
      }
    ],
    "user-auth-service": [
      {
        "key": "compliance-status",
        "value": {
          "certified": "SOC2",
          "last-audit": "2025-03-15",
          "reviewed-by": "security-team"
        }
      }
    ]
  }
}
```

Each tag can include multiple key-value objects, following the same shape as the single upload API.

### Defining custom data via webhook

Refer to [Custom webhook integrations](/ingesting-data-into-cortex/integrations/webhook)

## Data source hierarchy

When the same key is defined from multiple sources, Cortex resolves conflicts in the following order:

1. **Entity descriptor (YAML)** - The source of truth. Keys defined here cannot be overridden by the API or webhooks by default. Use `force=true` to override them via API, but note that the forced value will be overwritten the next time the entity descriptor is re-processed.
2. **API and webhooks** - Treated equally; either can override the other.

## Use cases

Custom data is flexible by design. Below are two of the most common ways teams put it to work.

### Cataloging

Cortex catalogs surface a lot out of the box—ownership, integration data, and more—but you may have internal fields that don't map to any integration. Custom data fills that gap. Common examples include:

* ***Which AWS zones is this deployed in?***
* ***What databases does this entity consume?***
* ***When was the last successful CI run?***

If the answers fit a fixed list, consider using [groups](/ingesting-data-into-cortex/entities-overview/entities/groups) instead. They display on an entity's details page and work well as catalog filters. Custom data is better suited for flexible or freeform values.

Once defined, custom data can be queried with the [Query builder](/standardize/cql#the-query-builder-tool), explored via [CQL reports](/standardize/cql/cql-reports), viewed directly on an [entity's details page](/ingesting-data-into-cortex/entities-overview/entities/details), or added as a column in Data Explorer's [table view](/improve/eng-intelligence/data-explorer#configuring-table-view).

### Scorecards

Custom data integrates directly with Scorecards. When [adding a rule](/standardize/scorecards/create#step-3-create-a-rule), select **Custom data** from the **Integrations** drop-down menu. Cortex automatically surfaces variables based on the custom data you've defined.

<div align="left" data-with-frame="true"><figure><img src="/files/l8tiOvtSFPYiEOaFPIf6" alt="The &#x27;Custom data&#x27; option selected in the Integrations drop-down menu." width="563"><figcaption></figcaption></figure></div>

For more advanced use cases, push JSON payloads via the [custom data API](/api/readme/custom-data) and process them in a Scorecard using `jq`, or pass them as input to a custom OPA policy rule.


# Discovered entities

Formerly 'Discovery audit'

You may have over a hundred repositories in GitHub, dozens of cloud resources across AWS, and services running in Kubernetes; eventually, you'll likely want all of them accounted for in Cortex. With that much information, it can be hard to know at a glance that everything is tracked and that new projects are being brought into your catalogs.

The discovered entities list (formerly known as the discovery audit) gives you confidence in your catalogs by surfacing every change Cortex detects across your environment. Cortex continuously compares what already exists in your catalog against what it finds in your connected integrations—your git provider, APM tools, Kubernetes clusters, cloud accounts, and other key integrations—so you always have insight into what's new or has changed.

## Viewing discovered entities

Users with the `View Entities` permission can view discovered entities.

**To access discovered entities**:

1. From the main sidebar, expand **Catalogs**, then select **All entities**.
2. Select the **Discovered entities** tab.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/uckBYzXysv3pZrPsFIx1" alt="The &#x27;Discovered entities&#x27; tab." width="375"><figcaption></figcaption></figure></div>

The tab opens to the **Discovered** view, which lists recent changes in your environment that aren't yet reflected in Cortex, such as newly created repositories and cloud resources discovered from your integrations. Events you've chosen to ignore live under the **Ignored** view instead.

Each row in the list shows:

* **Entity** - The name of the discovered entity, prefixed with an icon for the integration it came from (e.g. GitHub or AWS).
* **Event type** - The kind of change Cortex detected, such as **New repository** or **New AWS resource**.
* **Event date** - When the change was detected. Some sources don't report a timestamp, in which case this column shows N/A.
* **Actions** - The actions available for that event. The available actions depend on the event type: new resources can be imported or ignored, while resources that are no longer detected can be deleted or ignored. See [Acting on discovered entities](#acting-on-discovered-entities)&#x20;

### Searching and filtering the discovered entities list

The first time you view the discovered entities list, there may be a lot to review. To narrow the scope and start with the changes that are highest priority for you, search or filter the list.

* To search, type into the search bar in the upper-right corner of the list.
* To filter, click **Filter** in the upper-right corner of the list, then choose one or more of the following fields. Select your criteria, then click **Apply**. To clear everything and start over, click **Reset filters**.
  * **Integrations** - Limit the list to events from specific integrations
  * **Types** - Limit the list to specific event types

<div align="left" data-with-frame="true"><figure><img src="/files/9ezoCxk3CIhrnI3Iiu2h" alt="" width="375"><figcaption></figcaption></figure></div>

### Refreshing and exporting the discovered entities list

Two actions at the top of the list help you keep it current and share it:

* **Sync** - Prompts Cortex to re-check your connected integrations for changes, refreshing the list with the latest discovered events.
* **Export CSV** - Downloads the current list as a CSV file, which is useful for reviewing discovered entities offline or sharing them with your team.

<div align="left" data-with-frame="true"><figure><img src="/files/puUevk5zp8FsBwMV4y0S" alt="" width="375"><figcaption></figcaption></figure></div>

## Acting on discovered entities

`Admins` can act on discovered entities, i.e. import, ignore, and delete.

Each event offers a set of actions in the **Actions** column, depending on its type. You can import a newly discovered entity into Cortex, delete an entity that Cortex no longer detects, or ignore any event so it no longer appears in the list.

#### Importing an entity

If Cortex detects a new resource that you want to track, you can import it directly from this page:

1. Click the **import icon** in the **Actions** column of the row containing the entity. The **Import entities** page opens.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/SPB6YMy5xO1eEpwzmUDK" alt="" width="563"><figcaption></figcaption></figure></div>
2. Cortex opens the entity creation flow, prefilled with details from the discovered source. Configure the remaining entity details. For detailed instructions on creating each type of entity, see the relevant docs page: [Services](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/add-services), [Domains](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/domains), [Teams](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/teams), or [Custom entities](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/entity-types).
3. Click **Confirm import**.

When you import a discovered entity, Cortex generates a Cortex [entity descriptor](/ingesting-data-into-cortex/entities-overview/entities/yaml) (the cortex.yaml file) seeded with the discovered source. For example, importing a discovered AWS Lambda function as a resource might produce a descriptor like this:

```yaml
openapi: 3.0.1
info:
  title: Taylor Lambda
  description: Payment retry handler discovered from AWS
  x-cortex-tag: taylor-lambda
  x-cortex-type: resource
  x-cortex-definition:
    resourceType: lambda-function
  x-cortex-groups:
    - payments

```

{% hint style="info" %}
The import action isn't available for every event type. Rows where direct import doesn't apply show a disabled import icon.
{% endhint %}

### Ignoring an event

If an event appears in the list but isn't relevant, for example, a test repository that doesn't need to be imported into Cortex, you can ignore it by clicking the **eye icon** in the **Actions** column of the row containing the event. The event moves to the Ignored view. Ignoring is persistent, so the event won't reappear in the **Discovered** view.

To move an event back, open the **Ignored** view and click the **eye icon** in that row. The event returns to the **Discovered** view.

### Deleting an entity that is no longer detected

When Cortex stops detecting an entity that already exists in your catalog, e.g. its cloud resource was torn down or its APM service stopped reporting, the event appears with a **not detected** type, such as `AWS resource not detected`.&#x20;

**To delete the entity from the list**:

{% hint style="warning" %}
Deleting an entity is permanent. If you'd rather remove an entity from active use but keep it for historical reference, [archive it](/ingesting-data-into-cortex/entities-overview/entities/archiving-entities) instead of deleting it.
{% endhint %}

1. Click the **trash icon** in the **Actions** column of the row containing the entity. The **Confirm entity deletion** window opens.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/JTX3UZmiSo0NieRv82db" alt="" width="563"><figcaption></figcaption></figure></div>
2. Review the entity that will be removed (shown with its name and Cortex tag) so you don't unintentionally remove something that's still in use.
3. Click **Delete**.

For hands-off maintenance, you can also configure [auto-archival](/ingesting-data-into-cortex/entities-overview/entities/archiving-entities/auto-archive) to automatically archive entities when they're no longer detected in your integrations, so they never need to be cleaned up from this list manually.

## Troubleshooting and FAQ

See common frequently asked questions and troubleshooting information below.

**Why don't I see all of my services from my APM provider in the discovered entities list?**

Cortex supports discovery for a subset of integrations. If a service comes from an integration that isn't in the list below, it won't appear as a discovered entity:

* AWS
* Datadog
* ECS
* Google Cloud
* Instana
* Kubernetes
* Lightstep
* New Relic
* Version control (Azure DevOps, Bitbucket, GitHub, GitLab)

**Why is the import icon disabled for some rows?**

The import action is only available for event types that can be created directly from this page. When an event can't be imported this way, its import icon appears disabled. You can still bring the entity into Cortex through the standard [import flow](#importing-an-entity) or via [GitOps](/configure/gitops).

**What's the difference between ignoring and deleting an event?**

Ignoring an event simply hides it from the **Discovered** view and moves it to the **Ignored** view; it doesn't change anything in your catalog, and you can restore it at any time.&#x20;

Deleting is only available for entities Cortex no longer detects, and it permanently removes the entity from your catalog. If you want to keep an entity for historical reference, [archive it](/ingesting-data-into-cortex/entities-overview/entities/archiving-entities) instead of deleting it.


# Archiving entities

## Overview

Archiving an entity in Cortex hides it from view without losing any of its history or data, so you can always restore it later. Entities can be [archived manually](/ingesting-data-into-cortex/entities-overview/entities/archiving-entities/archiving-entities-manually) (one at a time or in bulk) or [automatically](/ingesting-data-into-cortex/entities-overview/entities/archiving-entities/auto-archive) when Cortex no longer detects them in your integrations or their YAML file is deleted. All changes are recorded in your audit log.

Auto-archival applies to entities that are no longer backed by any discovery provider (e.g., Git, Kubernetes, your cloud account). If one reappears, it's unarchived automatically. Entities that failed to sync due to errors are skipped, so a temporary integration issue won't cause anything to disappear. Admins can disable this behavior to manage archiving manually instead.

Archived entities are not included in the following Cortex features:

* Scorecards and Initiatives
* Reports
* Eng Intelligence
* Cortex Query Language (CQL) features, including CQL reports and query builder
* Relationship graphs
* Workflows

{% hint style="info" %}
Cortex tags detected changes to signify whether an entity or repository has been archived. Learn more in [Viewing discovered entities](/ingesting-data-into-cortex/entities-overview/entities/discovery-audit).
{% endhint %}

## Displaying archived entities in Cortex

### Displaying archived entities in the Entities list

By default, archived entities do not appear in the **All entities** list, but you can choose to include them in your view.

{% hint style="warning" %}
This setting resets when you leave the page, so you'll need to toggle it on it each time you want to view archived entities.
{% endhint %}

**To include archived entities**:

1. From the main sidebar, expand **Catalogs**, then select **All entities.**
2. At the top of the list, click **Display**.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/wOrInpSpB5jFm4lMGcnO" alt="The &#x27;Show archived&#x27; toggle turned on to include archived entities in the list." width="563"><figcaption></figcaption></figure></div>
3. Toggle on **Show archived**.

### Displaying an Archived label next to an entity

The **Overview** section on an [entity's details page](/ingesting-data-into-cortex/entities-overview/entities/details) only shows active dependencies, child entities, and parent entities; anything archived is hidden. If the entity itself is archived, an **Archived** label appears next to its name:

<div align="left" data-with-frame="true"><figure><img src="/files/wyywXnofEAqlexU2x2v7" alt="An archived entity has an &#x27;Archived&#x27; label next to its name." width="563"><figcaption></figcaption></figure></div>


# Archiving entities automatically

Cortex automatically archives entities when they're no longer detected in your integrations, so your catalog stays in sync as entities come and go. For example, if AWS auto-hydrates your catalog, enabling auto-archive will archive any entities that are later deleted from AWS.

This article covers how auto-archival works and how to configure it.

{% hint style="success" %}
It's highly recommended to enable this feature to keep your data up-to-date.
{% endhint %}

Cortex checks every day at 7 a.m. UTC for any affected entities, and skips archiving if any errors are detected.

## Enabling auto-archive of entities

Users with the `Edit Settings` permission can enable the auto-archive entities feature.

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 the **General** tab.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/gqTIGRf1BfamP8Jj8ayU" alt="The &#x27;General&#x27; tab within Cortex settings." width="238"><figcaption></figcaption></figure></div>
5. On the **General** page, scroll to the **Auto-archiving entities by type** section.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/mTZFBMSpUcjGFCQesDoJ" alt="The &#x27;Auto-archiving entities by type&#x27; section." width="375"><figcaption></figcaption></figure></div>
6. Toggle on any or all of the following:
   * **Enable integration-based auto-archiving for new entity types by default**
     * Toggle on this setting if you want to enable the feature for integration-based archiving. Cortex automatically archives and unarchives entities based on their existence in a third-party integration.
     * Cortex checks for a deleted or archived repo in your integration. To prevent an entity from being unarchived, make sure you have deleted the associated repo. The entity is removed the next time the archival sync runs.
     * This option is recommended if you use microservices that all live in different repos.
   * **Enable GitOps based auto-archiving for new entity types by default**
     * Toggle on this setting if you want to enable the feature for GitOps-based archiving. Cortex automatically archives entities if their corresponding YAML file is deleted.
     * If the file is moved rather than deleted, it is not archived from Cortex. Cortex checks for files that have been deleted.
   * **Auto-archive monorepo entities**
     * When enabled, if a monorepo is archived or unarchived, all entites in Cortex relating to that repo are automatically archived or unarchived.

{% hint style="info" %}
An entity's `x-cortex-tag` cannot be overwritten; attempting to update the `x-cortex-tag` value via GitOps creates a new entity. The entity only automatically archives if its original YAML file no longer exists in your Git environment.

To change an entity's `x-cortex-tag`, you must archive or delete the entity, then create a new entity with the desired tag.
{% endhint %}

## Enabling auto-archive per entity type

Users with the `Edit Settings` permission can enable auto-archive per entity type.

Below the auto-archive setting, each entity type (default and custom) is listed with its own toggle, so you can enable auto-archival selectively per type.

<div align="left" data-with-frame="true"><figure><img src="/files/vi4xOtd5IhgLlkoMXdlE" alt="Enable auto archive per entity type."><figcaption></figcaption></figure></div>

## Triggering an entity sync

Users need the `Edit Catalog` permission, combined with either:

* `Edit Domains`, `Edit Teams`, or `Edit Services` (depending on the entity type being archived), OR
* `Edit All Catalog`, which covers every entity type.

Deleted entities appear in the Entities list until the next time the auto-archival sync runs. You can also manually trigger the sync.

1. From the main sidebar, expand **Catalogs**, then select **All entities**.
2. In the upper right corner, click **Import entities**.
3. Select **Import discovered entities**.
4. Select an integration.\
   The **Select entities to import** window opens.
5. Click **Sync entities**.

## Troubleshooting and FAQ

**Why is an entity unexpectedly re-appearing after it's been archived?**

If you are using the integration-based auto-archiving, Cortex is checking whether the entity exists in your third-party integration. When Cortex runs the background sync for entity discovery, if the repo connected to that entity still exists, Cortex will un-archive the entity. To prevent un-archival, you can either delete the associated repo, or you can use the GitOps-based auto-archiving instead.

**Why is an entity still appearing after I deleted the YAML file for it or deleted the associated repo?**

The auto-archival feature runs once a day at 7 a.m. UTC. The entity appears until the next time the auto-archival sync runs or until you [manually trigger the sync](#trigger-an-entity-sync).


# Archiving entities manually

You might want to archive an entity before Cortex does it automatically, e.g. a service you're deprecating. This article covers how to archive and unarchive entities manually, individually or in bulk.

## Archiving an entity via the Cortex UI

Users with the `Archive Entities` permission can archive an entity.

1. From the main sidebar, expand **Catalogs**, then select **All entities**.
2. Do one of the following:
   * Select the **All** tab to search and filter across all of your organization's entities.
   * Select the **Mine** tab to search and filter only the entities you own.
   * Note that Cortex saves your selection and restores it the next time you open this page.
3. Select the entity you want to archive.
4. From the entity's details page, click the **overflow menu icon**.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/GQN7zYPldC9QUt2u4JSH" alt="The Overflow icon on an entity&#x27;s details page." width="563"><figcaption></figcaption></figure></div>
5. Select **Archive entity**.\
   The **Confirm entity archival** window opens.
6. Click **Archive**.\
   The entity is archived.

{% hint style="warning" %}
When an entity is archived, it no longer appears in the Entities list. Refer to [Displaying archived entities in the Entities list](/ingesting-data-into-cortex/entities-overview/entities/archiving-entities#displaying-archived-entities-in-the-entities-list).
{% endhint %}

### **Unarchiving an entity via the Cortex UI**

Users with the `Configure Entities` permission can unarchive an entity.

1. From the main sidebar, expand **Catalogs**, then select **All entities**.
2. Do one of the following:
   * Select the **All** tab to search and filter across all of your organization's entities.
   * Select the **Mine** tab to search and filter only the entities you own.
   * Note that Cortex saves your selection and restores it the next time you open this page.
3. At the top of the list, click **Display**.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/wOrInpSpB5jFm4lMGcnO" alt="The &#x27;Show archived&#x27; toggle turned on to include archived entities in the list." width="563"><figcaption></figcaption></figure></div>
4. Toggle on **Show archived**.
5. Select the entity from the Entities list.
6. From the entity's details page, click the **overflow menu icon**.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/lU30RWeZcyhvyHoOlR9g" alt="The Overflow icon on an entity&#x27;s details page." width="563"><figcaption></figcaption></figure></div>
7. Select **Unarchive entity**.\
   The **Confirm entity restoration** window opens.
8. Click **Restore**.\
   The entity is unarchived and moved back into the Entities list.

## Archiving an entity via the Cortex API

Refer to the API documentation on [archiving an entity](/api/readme/catalog-entities#put-api-v1-catalog-tagorid-archive) and [unarchiving an entity](/api/readme/catalog-entities#put-api-v1-catalog-tagorid-unarchive).


# Relationship graph

The relationship graph gives you a visual map of your Cortex catalog. Instead of reading dependencies, ownership, and architecture out of individual entity pages, you can see how everything connects in one interactive diagram.&#x20;

Use it to understand three different views of your organization:

* **Dependencies** - Visualize how entities depend on one another. You can also [sync dependencies](#sharing-or-syncing-from-the-graph) directly from the graph.
* **Domains** - See a hierarchical diagram of your software architecture.
* **Teams** - View your company's team structure and how teams nest within one another.

## Viewing the relationship graph

To access the relationship graph, expand **Tools** in the main sidebar, then click **Relationship graphs**. By default, the page loads [the view you've set as your default](#setting-the-default-view) (Dependencies, Domains, or Teams) and shows all entities in that view along with their connections.

Use the toolbar controls to move around the large graph:

* Use the zoom controls in the bottom-left corner to zoom in and out, fit the graph to the screen, or lock the view in place. If your mouse has a scroll wheel, you can also scroll to zoom in and out.
* Use the mini-map in the bottom-right corner to orient yourself and jump to another part of the graph.

### Choosing a relationship type

At the top-left of the page, use the view drop-down menu to switch between the three relationship types: Dependencies, Domains, and Teams. The available filters and display options change depending on which type you're viewing.

**Dependencies**

Visualize how entities relate to one another:

<div align="left" data-with-frame="true"><figure><img src="/files/C7cw4I6QCFcrhSpiItDE" alt="The relationship graph showing dependencies." width="563"><figcaption></figcaption></figure></div>

**Domains**

See a hierarchical diagram of your software architecture:

<div align="left" data-with-frame="true"><figure><img src="/files/l5y8tbDxt3KPJ1CMJiCU" alt="The relationship graph showing domains." width="563"><figcaption></figcaption></figure></div>

**Teams**

View your org's team structure:

<div align="left" data-with-frame="true"><figure><img src="/files/pvzOILSPnMUcQtK7ivtm" alt="The relationship graph showing teams." width="563"><figcaption></figcaption></figure></div>

### Searching and filtering the graph

**Searching**

Use the search bar at the top of the page to find and focus a single entity. Start typing an entity's name, then select it to center the graph on that entity and its connections.&#x20;

<div align="left" data-with-frame="true"><figure><img src="/files/Vb2UUidyfiwjMEojT1Uu" alt="The search bar on the relationship graph" width="375"><figcaption></figcaption></figure></div>

**Filtering**

{% hint style="info" %}
If your graph has more than 500 nodes, you must apply a filter before the graph displays.
{% endhint %}

Filters are available in the Dependencies and Domains views. Click **Filters** in the upper-right corner of the page, then narrow the graph with any combination of:

* **Sources** - Limit the graph to entities from specific data sources.
* **Groups** - Limit the graph to entities in specific groups.
* **Entity types** - Limit the graph to specific entity types.
* **Degrees from selected node** - This is unlocked when you select an entity node. Once you've selected an entity node, set how many connection hops out from that entity to display.

The graph applies your selections and reloads automatically. Click **Reset display** to clear all filters.

<div align="left" data-with-frame="true"><figure><img src="/files/eTiBBmXpwzP3fjTVYsur" alt="The filters option on the relationship graph." width="375"><figcaption></figcaption></figure></div>

### Choosing display options

Click **Display options** in the upper-right corner of the page to control how the graph is drawn. The options depend on which relationship type you're viewing.

<div align="left" data-with-frame="true"><figure><img src="/files/8Jso978kaWSLIdvhA9UO" alt="The display options on the relationship graph." width="375"><figcaption></figcaption></figure></div>

**In the Dependencies view**:

* **Show entity type icons** - Show or hide the icon on each node.
* **Show nodes without dependencies** - Show or hide entities that have no dependencies.
* **Scorecard** - Select a Scorecard to color and evaluate the graph against.

**In the Domains view**:

* **Show domain nodes without children** - Show or hide domains that contain no entities.
* **Show archived entities** - Include or exclude archived entities.
* **Scorecard** - Select a Scorecard to color and evaluate the graph against.

**In the Teams view**:

* **Show team nodes without children** - Show or hide teams that have no members or child teams.
* **Show archived entities** - Include or exclude archived entities.
* **Scorecard** - Select a Scorecard to color and evaluate the graph against.

Click **Reset display** to return to the default display options.

### Inspecting an entity

Click any node in the graph to open a quick-actions popup for that entity, where you can:

* **Filter by this node** - Refocus the graph on the selected entity. This also enables the **Degrees from selected node** filter so you can expand or contract how much of its network is shown.
* **Go to entity** - Open the entity's details page.

If the entity has dependencies or child entities, the popup also lists them. Click any item in the list to open that entity.

<div align="left" data-with-frame="true"><figure><img src="/files/vmXunea6rYsLItput7ue" alt="A selected node with the quick-actions popup displayed." width="375"><figcaption></figcaption></figure></div>

### Sharing or syncing from the graph

Click the **overflow menu icon** in the upper-right corner of the page to:

* **Share** - Share the current graph view.
* **Sync dependencies** - Users with the `Enable Entity Dependency Discovery` permission can manually sync dependencies. Cortex automatically syncs AWS dependencies every day at 8:00 a.m. UTC. All other dependencies sync at 12:00 a.m. UTC.

<div align="left" data-with-frame="true"><figure><img src="/files/ijwIKjYJkReTbt5izNTZ" alt="The overflow menu icon." width="563"><figcaption></figcaption></figure></div>

## Setting the default view

Users with the `Configure Settings` permission can set the default view of the relationship graph.

1. From the main sidebar, click your avatar in the bottom-left corner.
2. Click **Settings**.
3. From the **Settings** menu, locate the **Workspace** section, then click **Relationship graph**.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/hbvdNsmVRqwejDVEdTML" alt="The &#x27;Relationship graph&#x27; tab in the Settings." width="375"><figcaption></figcaption></figure></div>
4. Under **Select view**, choose which view (Dependencies, Domains, or Teams) opens by default when you navigate to the relationship graph.


# Using On-call Assistant for incident notifications

Cortex’s On-call Assistant leverages the [PagerDuty integration](/ingesting-data-into-cortex/integrations/pagerduty) to automatically surface the most vital information about entity health and metadata when an incident is triggered. On-call Assistant notifies the user(s) responsible for an incident via Slack, including information about the affected entity, recent deployments, ownership, and links to get more details, including dependencies, runbooks, and logs.

On-call Assistant helps users respond to incidents in real time, simplifying the incident response process and helping to reduce MTTR. It can also drive adoption and engagement through links to the catalogs and Scorecards.

{% hint style="info" %}
On-call Assistant only works for **service-level** PagerDuty registrations, since these notifications are related to affected services. Refer to [this article](/ingesting-data-into-cortex/integrations/pagerduty/connecting-entities-to-pagerduty#considerations-for-registering-pagerduty-entities) for more information.
{% endhint %}

## How On-call Assistant notifications are sent in Slack

When a PagerDuty incident is triggered, Cortex identifies the responsible on-call user and notifies them in Slack. The alert includes information about the affected entity, deploy details, and ownership information. A direct link is included to view the alert in PagerDuty, so the incident can be quickly assessed from its source.

**Individual users** - On-call Assistant sends a direct message (DM) to the on-call user. Users don't need to install the Cortex Slack app or select a channel. Cortex looks up the user's Slack account using the email address on their Cortex account, then sends the DM directly. The only requirement is that the user's email in Cortex matches their Slack workspace email.

**Teams** - Notifications are sent to the Slack channel or channels [configured on the entity](/ingesting-data-into-cortex/integrations/slack/using-the-integration-for-slack-ai-assistant#connecting-an-entity-to-a-slack-channel).

<div align="left" data-with-frame="true"><img src="/files/Y6kiXAoQphrCjOcPyHIW" alt="On-call assistant notifies users via Slack." width="375"></div>

### Viewing runbooks and other links

<div align="left" data-with-frame="true"><img src="/files/Y9t5j8pSNDwqleyvPg4l" alt="" width="563"></div>

### Viewing dependencies

<div align="left" data-with-frame="true"><img src="/files/9NpkbWQgzLufuFtJBISF" alt="" width="563"></div>

## Enabling On-call Assistant

### Prerequisites

1. An [API key](https://support.pagerduty.com/main/docs/api-access-keys#rest-api-keys) in PagerDuty with the `Write` permission.&#x20;
   * If you choose to bypass this prerequisite and create an API key with `Read-only` permissions, you also need to [configure a webhook](#configuring-a-webhook-for-read-only-api-keys) to get the On-call Assistant working.
2. The [PagerDuty integration](/ingesting-data-into-cortex/integrations/pagerduty) must be configured.
   * If using an API key with `Read-only` permission, be sure to toggle on **Read-only API key** in the PagerDuty side panel.<br>

     <div align="left" data-with-frame="true"><figure><img src="/files/ckhit4z3ilWuH6f6v7fu" alt="The &#x27;Read-only API key&#x27; option toggled on." width="113"><figcaption></figcaption></figure></div>
3. If sending notifications to teams, Slack channels must be [configured on the entity](/ingesting-data-into-cortex/integrations/slack/using-the-integration-for-slack-ai-assistant#connecting-an-entity-to-a-slack-channel).

### **Enabling On-call Assistant in Cortex**

1. From the main sidebar, select **Integrations**.
2. Locate PagerDuty, then click **Settings**.
3. Toggle on **Enable On-call Assistant**.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/Nx0Kwxj1zoLVwntC2Lqm" alt="The &#x27;Enable On-call Assistant&#x27; option toggled on." width="375"><figcaption></figcaption></figure></div>

#### Configuring a webhook for read-only API keys

If your PagerDuty API key has `Read-only` permissions, you must also configure a webhook subscription.

**Step 1: Enabling On-call Assistant in Cortex**

1. From the main sidebar, select **Integrations**.
2. Locate PagerDuty, then click **Settings**.
3. Toggle on **Enable On-call Assistant**. The **Configure webhook** side panel opens.

**Step 2: Adding a webhook in PagerDuty**

1. In PagerDuty, add a new [webhook](https://support.pagerduty.com/main/docs/webhooks):
   1. Under Webhook URL, paste the Cortex webhook URL. The Cortex webhook URL can be found in the **Configure webhook** side panel.<br>

      <div align="left" data-with-frame="true"><figure><img src="/files/qKd55tAmDK6qpFokYBjx" alt="The webhook URL." width="375"><figcaption></figcaption></figure></div>
   2. From the **Scope type** dropdown, select **Account**.
   3. Under **Event Subscription**, clear all checkboxes EXCEPT:
      * `incident.escalated`
      * `incident.reopened`
      * `incident.triggered`
      * `incident.unacknowledged`&#x20;
   4. Click **Add webhook**. The **Webhook subscription created** window opens.
   5. Copy the webhook secret. Don't skip this step! You'll need the webhook secret to complete the setup.
   6. Click **OK**.

**Step 3: Completing setup in Cortex**&#x20;

1. Go back to the browser window where your Cortex instance is open.
2. In the Configure webhook side panel, paste the webhook secret in the **Secret** field.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/QWvMm7TvgjOvTsB1eU2y" alt="" width="178"><figcaption></figcaption></figure></div>
3. Click **Save**.


# Managing Terraform infra in Cortex

Cortex Workflows can trigger Terraform execution to manage your cloud infrastructure, such as provisioning new services, databases, buckets, or networking primitives.

[Terraform](https://developer.hashicorp.com/terraform/intro) is an infrastructure-as-code tool that lets you provision, manage, and update infrastructure. Terraform can help you manage databases, s3 buckets, clusters, and every other component that comprises your infra. Terraform’s ability to manage resources comes from **providers**, which are plugins that enable interaction with cloud providers, SaaS providers, and other APIs. Providers allow you to define as code what a resource looks like.

The instructions on this page apply to [Terraform Cloud](https://developer.hashicorp.com/terraform/tutorials/cloud-get-started/cloud-sign-up), the web-based interface for Terraform.

{% hint style="info" %}
Cortex integrates with Terraform in two different ways, depending on whether you want to manage Cortex resources using Terraform or use Cortex to drive Terraform runs for your infrastructure.

To learn about managing Cortex resources using Terraform, see [Manage entities using Cortex Terraform Provider](/ingesting-data-into-cortex/entities-overview/entities/terraform/terraform-provider).
{% endhint %}

## How to manage Terraform infrastructure in Cortex

{% hint style="success" %}
See end-to-end examples for [using a Workflow to provision an EC2 instance with Terraform](https://github.com/cortexapps/hippocampus/blob/master/ingesting-data-into-cortex/entities/broken-reference/README.md), [using a Workflow to update the EC2 instance](https://github.com/cortexapps/hippocampus/blob/master/ingesting-data-into-cortex/entities/broken-reference/README.md), and [using a Workflow to destroy a resource](https://github.com/cortexapps/hippocampus/blob/master/ingesting-data-into-cortex/entities/broken-reference/README.md).
{% endhint %}

### Prerequisite

Expand the tile below for instructions on provisioning a new instance.

<details>

<summary>Provision a new instance and update the instance name</summary>

* Provision a new instance
  * Terraform will automatically provide you with a starter workspace when you begin — our example workspace is named **"tfc-guide-example"**.

<div align="left"><img src="/files/AejgHmD0hDWvaVHLkq2k" alt="Our example workspace is named &#x22;tfc-guide-example&#x22;" width="563"></div>

* Update the instance name in the Terraform `variables.tf` file.
  * All Terraform modules come with a file called `variables.tf`. As part of the Terraform script, we can enter variables for a given set, like region or instance type. In the example screen shot below, the variable name is "My Other Great Instance".

<div align="left"><img src="/files/ZzSxOI2nhsImuwyb8Bbj" alt="The variable instance name is &#x22;My other great instance.&#x22;" width="375"></div>

* Note: Terraform modules also come with a `main.tf` file, which contains instructions and information about the action. In our example, the `main.tf` file describes the instance that we’re going to create through Terraform.

![Example of the main.tf file](/files/SwpnYlI1U7NuusK2N33q)

{% hint style="info" %}
Terraform stores a “state” about your infrastructure and configuration when it’s deployed. State maps resources to this configuration, and will update any time variables or properties are changed.
{% endhint %}

</details>

### Step 1: Confirm your instance name update in Terraform

In Terraform Cloud, navigate to the **Run** page. Verify that the changes you made to the instance name in `variables.tf` have applied.

<div align="left"><img src="/files/vlr2ud7RS3Aen8dWGo4Y" alt="In Terraform, verify that your changes have applied." width="563"></div>

In Terraform, there are two primary commands: `plan` and `apply`.

* The `plan` command creates a plan and preview of the changes that will be made to your infrastructure. During the plan stage, Terraform assesses the `main.tf` file with variables and compares it against the state. If there are differences, Terraform prompts you to approve and apply the change.
* When you navigate to the run that was triggered by updating `variables.tf`, you can see that the plan was automatically conducted. In this case, the plan was to create an instance with the name provided earlier. Verify that the run displays a "Plan finished" message.

<div align="left"><img src="/files/lvqVS2Y1m6xSKgPTAYR2" alt="Terraform displays a &#x22;Plan finished&#x22; message." width="563"></div>

In AWS, you can confirm that the instance exists and that the Terraform action was successful:

![AWS shows that the instance exists.](/files/tnBnVbv1bpFW2tOA7ORw)

{% hint style="info" %}
In this example, we made direct modifications to the main branch, but typically, you will edit a separate branch and create a pull request. This approach will run a plan in Terraform, but will not automatically apply changes.
{% endhint %}

### Step 2: Add the Terraform template in Cortex

Cortex not only integrates with Terraform, but can enhance your use of it. Once the integration is set up, you’ll use a [Scaffolder step in a Workflow](/streamline/workflows#scaffolder) to interact with Terraform.

You must have the `Configure Scaffolder templates` permission.

{% hint style="info" %}
When using the Scaffolder, it's best to edit a secondary branch and create a pull request — the Scaffolder will actually create the pull request for you, which someone else can approve to apply the changes.
{% endhint %}

1. Create a [Cookiecutter](https://www.cookiecutter.io/) JSON file that is equivalent to your Terraform module.
   * In this file, we defined the region and instance name. You’ll then update the fields in the `variables.tf` file so it knows to pull information from the Cookiecutter JSON.\
     ![](/files/yq0nCQXZqRi44UCLroZT)
2. [Register your template](/streamline/workflows/scaffolder#step-2-add-the-template-to-cortex) in Cortex.
3. After you have added the template to Cortex, you can [create a Workflow](/streamline/workflows) that includes a [Scaffolder](/streamline/workflows#scaffolder) block using the template.
4. Run the Workflow. When you run it, Cortex will automatically open a pull request against the selected repository.

#### Verify that the process worked

<details>

<summary>Verify the process</summary>

To verify that the process worked, open Terraform Cloud and navigate to **Runs**.

Any runs that originate from Cortex will have `[Cortex Scaffolder]` at the start of their name. Click into one of these runs to see its status and how many changes were proposed.

<div align="left"><img src="/files/Lf9dAXnx0JrE6JaT6gr6" alt="A Cortex Scaffolder run shows as planned and finished in Terraform." width="563"></div>

</details>

## Execute a run via a Workflow

Terraform Cloud also has an API that can be used to make updates without following the pull request workflow. You can use a [Workflow](/streamline/workflows) in Cortex to execute a run through the API. If a run is set to automatically apply, then Cortex will handle the rest of the process.

1. [Create a Workflow](/streamline/workflows) in Cortex.
2. Add a [user input](/streamline/workflows#user-input) block.
   1. Define inputs for `Instance name`, `Region`, and `Instance type`.
3. Add an [HTTP request](/streamline/workflows#http-request) block. Configure the following fields:
   1. **HTTP method**: Select `POST`.
   2. **URL**: Enter the URL for the Terraform API you want to call.
   3. **Headers**: Add `Authorization: Bearer {{token}}` and `Content-type: application/(name)`.
   4. **Payload**: Build the payload by referencing the outputs of the "User input" block, e.g., `{{actions.input.outputs.instance-name}}`
4. Save the Workflow. After saving, click **Run** at the top of the Workflow to run it.

When the Workflow is run in Cortex, it will override data in the `variables.tf` file with information that was entered in the fields.

#### Verify the run

<details>

<summary>Verify that the action was successful</summary>

In Terraform Cloud, you can verify that the action was successful and the run was queued. Runs triggered by actions are named "Triggered via API."

<div align="left"><img src="/files/y9nEFfB1mPitCsrkXltj" alt="The run in Terraform is labeled &#x22;Triggered via API.&#x22;" width="563"></div>

Once the run has been applied, you can also verify it in AWS. In the example screen shot below, the instance name has been changed:

![The instance is listed in AWS.](/files/V2UO1vlYEs0cvITqFe2j)

</details>

## Terraform Workflow examples

See guides on creating the following Workflows: [Provision EC2 instance with Terraform](/guides/production-readiness/terraform/provision), [Update EC2 instance](/guides/production-readiness/terraform/update), and [Terraform destroy](/guides/production-readiness/terraform/destroy).


# Manage entities using Cortex Terraform Provider

The [Cortex Terraform Provider](https://github.com/cortexapps/terraform-provider-cortex) acts as a bridge between Terraform and the Cortex platform, allowing you to manage and provision Cortex resources (such as [Scorecards](/standardize/scorecards), [integrations](/ingesting-data-into-cortex/integrations), and [entities](/ingesting-data-into-cortex/entities-overview/entities)) using Terraform’s infrastructure-as-code approach. The provider is a wrapper around the public Cortex API and is maintained by the Cortex team, with shared ownership and ongoing support for customers who use it.

{% hint style="info" %}
Cortex integrates with Terraform in two different ways, depending on whether you want to manage Cortex resources using Terraform, or use Cortex to drive Terraform runs for your infrastructure.

To learn about using Cortex to drive Terraform runs, see [Managing Terraform infra in Cortex](/ingesting-data-into-cortex/entities-overview/entities/terraform).
{% endhint %}

### Managing the catalog as code

Many Cortex customers manage their entire service catalog and engineering standards as code using the Cortex Terraform Provider.

Expand the tiles below for examples on how to handle different use cases with this approach.

<details>

<summary>Service catalog as code</summary>

**Goal:** Any time a new microservice or app is created (via a Terraform module, template repo, or platform workflow), it’s automatically added to the Cortex catalog with the right metadata and ownership.\
\
**How to do it:**

* Use the `cortex_catalog_entity` resource to create and update services, libraries, or other catalog entities from Terraform.
* Attach extra metadata with `cortex_catalog_entity_custom_data` – e.g. `tier`, `business_unit`, `cost_center`, “is\_internally\_facing”, etc.
* Optionally define departments (e.g. “Payments”, “Growth”) with `cortex_department`, and link services/teams to those for reporting and ownership.

</details>

<details>

<summary>Scorecards and standards as code</summary>

**Goal**: Treat operational standards (SRE, security, compliance, production-readiness gates) as code that lives next to infrastructure, reviewed via PRs and rolled out safely.\
\
How to do it:

* Define scorecards via the `cortex_scorecard` resource. It supports:
  * a ladder (levels with names, colors, rank)
  * rules (expressions, titles, weights, optional failure messages)
  * an evaluation window (how often to evaluate, min every 4 hours)
  * a filter to target specific entity types or groups
* Use `cortex_resource_definition` to standardize external signals that Scorecards rely on (e.g. “has SLO in Datadog”, “has PagerDuty service”, “has runbook link”).
* Manage changes to standards through Git review: PRs update the Terraform code, then Terraform updates the Cortex Scorecards and resources.

</details>

<details>

<summary>API contracts and org model as code</summary>

**Goal**: Ensure that API documentation and org metadata are always in sync, accurate, and consistent across environments.\
\
How to do it:

* Use `cortex_catalog_entity_openapi` to attach OpenAPI specs (YAML/JSON) to catalog entities in Cortex, keyed by the entity’s tag/ID.
* Keep department and ownership structure in Terraform via `cortex_department` and catalog entity custom data (e.g., `department`, `team`, `criticality`).
* When infrastructure changes (e.g., new API version, team moves between org units), updating Terraform automatically pushes the new OpenAPI spec + org metadata into Cortex.

</details>

## Install the Terraform Provider for Cortex

For installation instructions, see the [repository's README in GitHub](https://github.com/cortexapps/terraform-provider-cortex).

### Examples

See [the repository for examples](https://github.com/cortexapps/terraform-provider-cortex/tree/main/examples).


# Catalogs overview

Using catalogs to organize and manage entities in Cortex

A catalog is a defined selection of [entities](/ingesting-data-into-cortex/entities-overview). Use catalogs to track and store information about all the components that make up your infrastructure, from services and domains to Amazon Web Services (AWS) resources like S3 buckets and RDS instances, Google Cloud resources, and Azure resources.

Entities are [defined by YAML files](/ingesting-data-into-cortex/entities-overview/entities/yaml), but catalogs aren't. You create catalogs in the Cortex UI. Think of a catalog as a folder containing a collection of entities, with each entity defined by its own YAML file. Since an entity can belong to multiple catalogs, you can also think of a catalog as a filter that determines which entities get grouped together.

In the screenshot below, the **Services** page contains a list of all entities that belong to the `service` catalog:

<div align="left" data-with-frame="true"><figure><img src="/files/ULPVbUYjJlW0JUPU0IKi" alt="The services catalog displays a list of services." width="563"><figcaption></figcaption></figure></div>

Watch the video below for an overview of how Cortex helps you build and catalog your engineering operations assets, improving visibility, adoption, and productivity.:

{% embed url="<https://www.youtube.com/watch?v=A5w6ebxGbeg>" %}

{% hint style="success" %}
Want to learn more? Check out the Cortex Academy [course on Catalogs](https://academy.cortex.io/courses/introduction-to-catalogs).
{% endhint %}

## Working with catalogs

By default, Cortex comes with four built-in catalogs:

* **Services** - Contains all [service entities](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/add-services).
* **Infrastructure** - Contains all entities representing your infrastructure assets.
  * Cortex pulls in resources directly from [AWS](/ingesting-data-into-cortex/integrations/aws), [Azure Resources](/ingesting-data-into-cortex/integrations/azureresources), or [Google Cloud](/ingesting-data-into-cortex/integrations/google), as their corresponding types out of the box. These resources are automatically added to the Infrastructure catalog.
* **Domains** - Contains all [domain entities](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/domains) and their children entities (regardless of entity type), and displays them in a hierarchical view.
* **Teams** - Contains all [team entities](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/teams) and displays them in a hierarchical view alongside a leaderboard based on Scorecards.

You can rename these catalogs to fit your own taxonomy. Keep in mind that custom names for default catalogs won't override references to their default names elsewhere in the app. If you want more flexibility, create additional custom catalogs instead.

### Catalog types

Cortex supports two types of catalogs: entity type catalogs and relationship type catalogs.

* **Entity type catalogs** define entity inclusion criteria using filters for entity type, tags, or groups. For example, the built-in **Service** catalog is configured to include entities of type `service`.
* **Relationship type catalogs** group entities based on a specific [entity relationship type](/ingesting-data-into-cortex/entities-overview/entities/defining-relationship-types). These catalogs support visualizing hierarchical relationships and let different entity types relate to one another. For example, the built-in **Domain** catalog includes entities connected through a parent/child domain relationship. It displays every entity in the domain hierarchy, including entity types that aren't domains.


# Viewing catalogs

This article explains how to view, search, filter, and sort catalogs.

## Configuring the catalog display in the main sidebar

Users with the `Configure Appearance Settings` permission can configure the catalog display.

By default, catalogs appear in alphabetical order in the main sidebar, but you can manually reorder them.

1. From the main sidebar, click your avatar in the bottom-left corner.
2. Select **Settings**.
3. Locate the **Workspace** section, then select **Main sidebar**.
4. From the **Catalogs** tab, drag and drop catalogs into your preferred order.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/QiGTHclC5UBn2tPSZZQT" alt="" width="375"><figcaption></figcaption></figure></div>
5. Click **Save changes**.

## Viewing catalogs

### Accessing catalogs

Users with the `View Catalogs` permission can view a catalog's entities list. To access an entity list, expand **Catalogs** from the main sidebar:

<div align="left" data-with-frame="true"><figure><img src="/files/yNbq8Qsj7VJOLVEsEOA9" alt="The &#x27;Catalogs&#x27; tab in the main sidebar." width="563"><figcaption></figcaption></figure></div>

### Viewing all catalogs

The **All catalogs** page shows the same list of catalogs as the **Catalogs** dropdown in the main sidebar. It includes a search bar and a sort by name function, as well as a toggle for displaying or hiding drafts (click **Display**). From this page, you can create new catalogs and edit existing ones.

<div align="left" data-with-frame="true"><figure><img src="/files/c7Af2QqY7oodmJsFglrs" alt="The search and filter options on the &#x27;All catalogs&#x27; page." width="563"><figcaption></figcaption></figure></div>

### Viewing all entities

The **All entities** page includes every entity across all catalogs and entity types. To view all entity types, select the **Entity types** tab at the top of the page.

<div align="left" data-with-frame="true"><figure><img src="/files/GShoON9Ta6kqFDRWUras" alt="The &#x27;All entities&#x27; page." width="563"><figcaption></figcaption></figure></div>

Like the **All catalogs** page, **All entities** includes search, filter, and sort options.

{% hint style="info" %}
Select the **All** tab to view all entities. Select the **Mine** tab to view only entities where you are an owner or member. Cortex saves your selection and restores it the next time you open this page.

<img src="/files/XPX1ltM1su6PpTkrfvfN" alt="" data-size="original">
{% endhint %}

### Viewing a specific catalog

Select a catalog to view all of its entities:

<div align="left" data-with-frame="true"><figure><img src="/files/kpJWTfTd03gWgqvYldZ6" alt="The &#x27;Domains&#x27; catalog." width="563"><figcaption></figcaption></figure></div>

### Searching across and filtering entities

Cortex offers several ways to search and filter entities, and the available options depend on the entity type you're viewing. For details on search and filter options for each entity type, see:

* [Services](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/add-services#searching-across-and-filtering-services)
* [Domains](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/domains#searching-across-and-filtering-domains)
* [Teams](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/teams/viewing-teams#searching-across-and-filtering-teams)

<div align="left" data-with-frame="true"><figure><img src="/files/ztKbHYwqWhy0PubZMvec" alt="The &#x27;Display&#x27; option at the top of a catalog." width="563"><figcaption></figcaption></figure></div>

At the top of a catalog, click **Display** to turn on options like showing archived entities or switching between hierarchical and list views (availability depends on entity type). Click **Filter** to narrow the list by associated Git repository, unowned entities, AWS account ID or region, domain, entity type, group, team, or user.


# Managing catalogs

This article covers how Cortex assigns entities to catalogs automatically, plus how to create, edit, delete, and track changes to your own catalogs.

## Adding an entity to a catalog

After Cortex imports or creates an entity, it automatically assigns the entity to a catalog based on that catalog's entity type criteria. When you [create a custom catalog](#creating-a-custom-catalog), you can define its entity type criteria.

Default catalogs come with preset entity type criteria:

* The **Services** catalog contains `service` entities.
* The **Domains** catalog contains `domain` entities.
* The **Teams** catalog contains `team` entities.
* The **Infrastructure** catalog contains any entity that isn't type `service`, `domain`, or `team`.

[Custom entity types](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/entity-types) belong to the **Infrastructure** catalog by default. To move a custom entity type to a different catalog, add it there directly.

## Creating a custom catalog

Users with the `Edit Catalogs` permission can create, edit, or delete catalogs

You can create catalogs in the Cortex UI. For each catalog, you set the criteria that determine which entities belong to it. You can also define custom entity types to categorize the entities in your catalogs.

Because catalogs aren't defined by a YAML file, you can't create them through a GitOps workflow.

**To create a new catalog**:

1. From the main sidebar, expand **Catalogs**, then select **All catalogs**.
2. In the upper-right corner, click **Create catalog**.
3. On the **Create new catalog** page, do the following:
   1. In the **Details** section:
      1. Under **Catalog name**, enter a new name for the catalog (required).
      2. Under D**escription**, enter an overview of the catalog.
      3. Under **URL**, enter a custom URL for the catalog. By default, the URL matches the catalog name. If the URL is updated, the latest URL will be activated immediately, and any previous URL navigates to the catalog list page as a fallback.
         * **Example** - For a catalog named "ML Models", the auto-generated slug might be `ml-models`, resulting in a URL like: `https://app.getcortexapp.com/admin/catalog/ml-models` . You could customize the slug to something like `machine-learning`, giving you: `https://app.getcortexapp.com/admin/catalog/machine-learning`.
      4. Under **Display icon**, select an icon to represent the catalog.
   2. In the **Catalog filter** section:
      1. From the **Entity type** tab, select one or more entity types to include their respective entities in the catalog. You can select entity types manually, or use advanced options like a `CQL` expression. Every entity that matches the criteria you set here is automatically included. Choose one filter type: entity type or relationship type.
         * Optionally, expand **Advanced options** to refine entity selection by applying additional filters for groups or a `CQL` expression. You can also skip other filters entirely and use a `CQL` expression alone to define the entity type selection.
      2. From the **Relationship type** tab, select a relationship type to filter which entities appear on the catalog page.
4. By default, **Draft** is toggled on. If you're ready to publish your changes, toggle it off.
5. Click **Create**.

New catalogs are found under **Catalogs > All catalogs**, automatically populated with entities that match your criteria. Catalogs with a relationship type filter display as a hierarchy.

## Editing a catalog

Users with the `Edit Catalogs` permission can edit a catalog's name, description, URL, display icon, and filter type.

1. From the main sidebar, expand **Catalogs**, then select the catalog you want to edit.
2. In the upper-right corner, click **Edit catalog**. The **Edit catalog** page opens.
3. Refer to step 3 in [Creating a custom catalog](#creating-a-custom-catalog) for detailed information.
4. Optionally, toggle on **Draft** to save your changes without publishing them.
   * When you're ready to publish, toggle off **Draft**, then click **Save**.
5. Click **Save**.

## Deleting a catalog

Users with the `Edit Catalogs` permission can delete a catalog.

{% hint style="warning" %}
You should only delete a catalog if you're absolutely sure it's no longer needed. Deleting a catalog does NOT delete the entities in that catalog.
{% endhint %}

1. From the main sidebar, expand **Catalogs**, then select the catalog you want to delete.
2. In the upper-right corner, click **overview menu icon**.
3. Select **Delete catalog**. The **Delete catalog** window opens.
4. Click **Delete**.

## Tracking catalog changes

Use the [audit log](/configure/settings/audit-logs) to track changes made to any of your catalogs. Catalog updates are listed as `CATALOG` in the **Object type** column. The **Action type** column indicates whether a catalog was created, deleted, or updated.


# Integrations

**Seamlessly connect your entire stack**

Cortex supports a broad set of [third-party](#third-party-integrations), [internally hosted](#internally-hosted-integrations), and [custom webhook](#custom-webhook-integration) integrations designed to meet your engineering organization where it already works. Whether you're connecting source control, CI/CD pipelines, incident management tools, or cloud infrastructure providers, Cortex fits into your existing workflows without significant setup overhead or custom development.

**Key Benefits**

* **Centralized data synchronization**. Aggregate data from across your toolchain into a single, unified view. Eliminate the need for manual data collection and reduce the risk of fragmented or inconsistent reporting.
* **Flexibility at scale**. Cortex supports organizations of all sizes, offering both out-of-the-box integrations and extensible configurations for teams with more specialized tooling requirements.
* **Minimal operational overhead**. Once configured, integrations run continuously in the background, keeping your platform data fresh and reliable without ongoing maintenance from your team.
* **Secure and compliant by design**. All integration connections are established using industry-standard authentication protocols, ensuring your data is transmitted and stored in accordance with your organization's security requirements.

<div align="left" data-with-frame="true"><figure><img src="/files/41GhSHvaQzG0ST1reCOc" alt=""><figcaption></figcaption></figure></div>

Users can view the Integrations page to check which integrations are configured and monitor their health status. To install, uninstall, or modify integrations, users must have the `Configure Integrations` permission.

{% hint style="info" %}
Integration sync times vary and are subject to scheduling overrides and timing variance.
{% endhint %}

## Third-party integrations

Cortex connects to each tool via its official API, pulling live data directly from your systems. When viewing an entity, the information displayed reflects the current state of your tools—no manual syncing or stale data to manage.

Cortex integrates with tools across the core domains of engineering operations, including:

### Essentials

<details>

<summary>Version control</summary>

* [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)

</details>

<details>

<summary>Team/Ownership</summary>

* [Azure DevOps](/ingesting-data-into-cortex/integrations/azuredevops)
* [BambooHR](/ingesting-data-into-cortex/integrations/bamboohr)
* [Entra ID (formerly Azure Active Directory)](/ingesting-data-into-cortex/integrations/entraid)
* [GitHub](/ingesting-data-into-cortex/integrations/github)
* [GitLab](/ingesting-data-into-cortex/integrations/gitlab)
* [Google](/ingesting-data-into-cortex/integrations/google)
* [Okta](/ingesting-data-into-cortex/integrations/okta)
* [Opsgenie](/ingesting-data-into-cortex/integrations/opsgenie)
* [ServiceNow](/ingesting-data-into-cortex/integrations/servicenow)
* [Workday](/ingesting-data-into-cortex/integrations/workday)

</details>

<details>

<summary>On-call</summary>

* [PagerDuty](/ingesting-data-into-cortex/integrations/pagerduty)
* [Opsgenie](/ingesting-data-into-cortex/integrations/opsgenie)
* [Splunk On-Call (formerly VictorOps)](/ingesting-data-into-cortex/integrations/splunk-oncall)
* [xMatters](/ingesting-data-into-cortex/integrations/xmatters)

</details>

<details>

<summary>Project management</summary>

* [Azure DevOps](/ingesting-data-into-cortex/integrations/azuredevops)
* [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)

</details>

<details>

<summary>Communication</summary>

* [Slack](/ingesting-data-into-cortex/integrations/slack)
* [Microsoft Teams](/ingesting-data-into-cortex/integrations/microsoftteams)

</details>

<details>

<summary>Code quality</summary>

* [Codecov](/ingesting-data-into-cortex/integrations/codecov)
* [SonarQube](/ingesting-data-into-cortex/integrations/sonarqube)

</details>

### Extended

<details>

<summary>CI/CD</summary>

* [ArgoCD](/ingesting-data-into-cortex/integrations/argocd)
* [Azure DevOps](/ingesting-data-into-cortex/integrations/azuredevops)
* [Buildkite](/ingesting-data-into-cortex/integrations/buildkite)
* [CircleCI](/ingesting-data-into-cortex/integrations/circleci)
* [GitHub](/ingesting-data-into-cortex/integrations/github)
* [Jenkins](/ingesting-data-into-cortex/integrations/jenkins)

You can also use Cortex's [deploys API](/api/readme/deploys) to send deployment data from other services to Cortex.

</details>

<details>

<summary>Cloud</summary>

* [AWS](/ingesting-data-into-cortex/integrations/aws)
* [Azure Resources](/ingesting-data-into-cortex/integrations/azureresources)
* [Google](/ingesting-data-into-cortex/integrations/google)
* [Kubernetes](/ingesting-data-into-cortex/integrations/kubernetes)
* [Syntasso Kratix Enterprise (SKE)](/ingesting-data-into-cortex/integrations/syntasso)

</details>

<details>

<summary>Error tracking</summary>

* [BugSnag](/ingesting-data-into-cortex/integrations/bugsnag)
* [Rollbar](/ingesting-data-into-cortex/integrations/rollbar)
* [Sentry](/ingesting-data-into-cortex/integrations/sentry)

</details>

<details>

<summary>Feature flags</summary>

* [LaunchDarkly](/ingesting-data-into-cortex/integrations/launchdarkly)

</details>

<details>

<summary>Incidents</summary>

* [FireHydrant](/ingesting-data-into-cortex/integrations/firehydrant)
* [Incident.io](/ingesting-data-into-cortex/integrations/incidentio)
* [PagerDuty](/ingesting-data-into-cortex/integrations/pagerduty)
* [Rootly](/ingesting-data-into-cortex/integrations/rootly)

</details>

<details>

<summary>Observability</summary>

* [Coralogix](/ingesting-data-into-cortex/integrations/coralogix)
* [Datadog](/ingesting-data-into-cortex/integrations/datadog)
* [Dynatrace](/ingesting-data-into-cortex/integrations/dynatrace)
* [Google Observability Cloud](/ingesting-data-into-cortex/integrations/google)
* [Instana](/ingesting-data-into-cortex/integrations/instana)
* [New Relic](/ingesting-data-into-cortex/integrations/newrelic)
* [Prometheus](/ingesting-data-into-cortex/integrations/prometheus)
* [ServiceNow Cloud Observability (formerly Lightstep)](/ingesting-data-into-cortex/integrations/lightstep)
* [Splunk Observability Cloud (formerly SignalFX)](/ingesting-data-into-cortex/integrations/splunk-observability)
* [Sumo Logic](/ingesting-data-into-cortex/integrations/sumologic)

</details>

<details>

<summary>Security</summary>

* [Apiiro](/ingesting-data-into-cortex/integrations/apiiro)
* [Checkmarx](/ingesting-data-into-cortex/integrations/checkmarx)
* [GitHub](/ingesting-data-into-cortex/integrations/github)
* [GitLab](/ingesting-data-into-cortex/integrations/gitlab)
* [Mend](/ingesting-data-into-cortex/integrations/mend)
* [Semgrep](/ingesting-data-into-cortex/integrations/semgrep)
* [Snyk](/ingesting-data-into-cortex/integrations/snyk)
* [Veracode](/ingesting-data-into-cortex/integrations/veracode)
* [Wiz](/ingesting-data-into-cortex/integrations/wiz)

</details>

<details>

<summary>ITSM</summary>

* [ServiceNow](/ingesting-data-into-cortex/integrations/servicenow)

</details>

### Configuring third-party integrations

Cortex integrates with a wide range of third-party tools to surface relevant data across your workspace.

#### **Adding an integration**

Users with the `Configure Integrations` permission can install integrations.

1. From the main sidebar, select **Integrations**.
2. Locate the integration you want to set up, then click **Install**.

Specific configuration steps and required credentials vary by integration.

#### **Modifying an integration configuration**

You can edit an existing configuration directly, including credentials, without deleting and re-adding it. This applies to both single and multi-configuration integrations.

Users with the `Configure Integrations` permission can modify integrations.

{% hint style="info" %}
**The following third-party configurations cannot be modified**

OAuth-based configurations cannot be directly modified. To make changes, you'll need to delete and re-install the integration, since setup requires a third-party redirect. This applies to: Bitbucket Atlassian App, GitHub App, Kubernetes (which uses its own unique flow), Microsoft Teams, and Slack.

Additionally, configuration management isn't available for ArgoCD, Grafana, Humanitec, and Syntasso.
{% endhint %}

1. From the main sidebar, select **Integrations**.
2. Locate the integration you want to edit, then click **Settings**.
3. Find the configuration you want to edit, then click the **pencil icon**.
4. Make your changes, then click **Save**.

**A note about deleting and re-installing integrations**

If your third-party integration can't be modified in Cortex, you'll need to delete and re-install it.

Helpful tips include:

* Use the same alias name. Delete the old integration configuration in Cortex and re-install using the same alias, e.g. `cortex-github`.
* If you had multiple configurations for this integration, and the integration with the expired key was set as the default, set the new configuration as the default. This helps avoid disruptions to dependent workflows or entities, as entities will fall back to the default configuration if their YAML file references an alias that doesn't exist.
* Monitor the new integration configuration.

#### **Removing an integration configuration**

Users with the `Configure Integrations` permission can remove an integration configuration.

1. From the main sidebar, select **Integrations**.
2. Locate the integration you want to remove, then click **Settings**.
3. Find the configuration you want to edit, then click the **trash icon**.\
   The **Confirm configuration removal** window opens.
4. Click **Delete**.

#### **Managing integrations via the API**

You can also manage integration configurations programmatically using the Cortex API which is useful for codifying integration setup, syncing configurations across environments, or automating credential rotation.

The API supports listing, creating, updating, and deleting configurations for the following integrations:

* AWS, Azure DevOps, Azure Resources, Bitbucket, Buildkite, CircleCI, Coralogix, Datadog, Entra ID, GitHub, GitLab, incident.io, Jira, LaunchDarkly, Mend, New Relic, PagerDuty, Prometheus, Semgrep, SonarQube, and Wiz.

For all other integrations—including OAuth-based ones like the GitHub App, Bitbucket Atlassian App, Microsoft Teams, and Slack—use the UI to install and configure.

See the [Cortex API reference](https://docs.cortex.io/api/readme/integrations) for endpoint details and authentication.

## Internally hosted integrations

If your tooling is hosted within your own infrastructure rather than the cloud, Cortex can still connect to it. Internally hosted integrations allow you to source data from systems running behind your firewall or private network and reflect that data in Cortex, giving you the same visibility and platform functionality without requiring your tools to be publicly accessible.

**Example use case**

If your team runs tools like GitLab, Jenkins, or Jira on private infrastructure rather than in the cloud, or relies on proprietary internal tooling for tracking services, deployments, or ownership, internally hosted integrations allow Cortex to pull in that data without requiring those systems to be publicly accessible.

See [Internally hosted integrations](/ingesting-data-into-cortex/integrations/axon-relay) for more information.

## Custom webhook integrations

Custom webhook integrations allow you to send data to Cortex from virtually any source, including internal tooling or systems that don't have a native Cortex integration. Each webhook generates a unique URL that accepts arbitrary JSON payloads via `POST`—no authentication headers or Cortex entity tags required. This makes custom webhooks a flexible option for teams that need to pipe in data from homegrown tools, scripts, or automated workflows that fall outside Cortex's standard integration offerings.

**Example use case**

If your team uses an internal deployment tool that isn't supported as a native integration, you can configure it to `POST` deployment events directly to your custom webhook URL, making that data available within Cortex without any additional middleware.

See [Custom webhook integrations](/ingesting-data-into-cortex/integrations/webhook) for more information.

## SSO integrations for Cortex workspace access

Single sign-on (SSO) allows users to authenticate with Cortex using the same credentials they already use across your organization's other tools and systems. Rather than managing a separate set of login credentials, users sign in once through your identity provider—such as Okta, Google, or Microsoft Entra ID—and gain access automatically. For organizations with strict security or compliance requirements, SSO also provides centralized control over user access, making it easier to provision and deprovision accounts as team members join or leave.

Cortex supports the following SSO integrations:

* [Microsoft Entra ID](/configure/settings/managing-users/configuring-sso/entraid)
* [Google](/configure/settings/managing-users/configuring-sso/google)
* [Okta](/configure/settings/managing-users/configuring-sso/okta)
* [Other OIDC providers](/configure/settings/managing-users/configuring-sso/oidc)

## SCIM integrations for provisioning users

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.

Cortex supports the following SCIM integrations:

* [Microsoft Entra ID](/configure/settings/managing-users/provisioning-users-with-scim/entraid-scim)
* [Okta](/configure/settings/managing-users/provisioning-users-with-scim/okta-scim)

See [Provisioning users with SCIM](/configure/settings/managing-users/provisioning-users-with-scim) for more information.

## Integration rate limiting

Cortex has built a distributed self-throttling system to ensure that certain functionality, such as CQL evaluations or background syncs to pull data from integrations, are not going over the rate limit thresholds for specific vendors. It handles different rate limit thresholds for different APIs within the same integration, which is common for git APIs such as Bitbucket.

The system is designed to proactively throttle before hitting a 429 from the vendor, and it works regardless of how many evaluators are trying to access that integration. Note that this system does not track other requests with the same token or undocumented limits set by vendors.

## Troubleshooting with integration logs

{% hint style="info" %}
This feature is available in Cortex cloud.
{% endhint %}

While viewing an integration's settings page, click the **Error Logs** tab to view error logs from the last 7 days. You can filter the logs list by configuration, by entity to see only the errors affecting a specific entity, and by operation (for example, you could filter to view errors surfaced only via Scorecards).

<div align="left" data-with-frame="true"><figure><img src="/files/LVuIIkN8LA3bZWUtUCI6" alt="Click the Error Logs tab on an integration to view integration logs and errors."><figcaption></figcaption></figure></div>

Click into a log to get more information, including time stamp, status code, full error, and request path.


# Internally hosted integrations

Cortex Axon is a framework that can be used to build jobs that run in your environment and securely send data to Cortex. It includes:

* **Custom handlers**: It makes it easy to write code against the Cortex API that can send data to Cortex either on a regular interval, a cron schedule, or after processing a webhook.
  * See the [Cortex Axon README](https://github.com/cortexapps/axon) for more information.
* **Internally-hosted integration support**: Using Axon Relay, it can provide a virtual connection between your network and Cortex. Use it to allow Cortex to access internally-hosted integrations for [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), [Prometheus](/ingesting-data-into-cortex/integrations/prometheus), and [SonarQube](/ingesting-data-into-cortex/integrations/sonarqube). You can also use Axon Relay to [call internal service endpoints via a Workflow](/guides/operational-readiness/internal-endpoints) in Cortex.
  * This documentation page walks you through configuring internal integrations with Axon Relay.

### How it works

<figure><img src="/files/nCtdduo63V1wd3NvwiKo" alt="Network diagram showing how Cortex Axon works."><figcaption></figcaption></figure>

Cortex Axon uses an open-source project published by Snyk called [Snyk Broker](https://docs.snyk.io/implementation-and-setup/enterprise-setup/snyk-broker). Snyk Broker uses WebSockets to create a secure tunnel between the internal network and cloud-hosted Cortex. HTTP requests are redirected through this WebSocket channel to the Axon agent. You do not need to open inbound firewall ports, as the tunnel is initiated from the internal network.

When deploying Axon, you provide your API tokens or credentials as secrets stored on infrastructure you own, within your network. Axon securely holds these credentials and uses them to proxy requests to third-party integrations. Your sensitive information stays inside your virtual private cloud (VPC) and is never exposed to Cortex cloud services.

This is what the process looks like:

1. On the Cortex side, you register the integration, using an alias name you provide.
2. The Cortex Axon Docker container is started with your Cortex API key, the integration type, and the alias.
3. The Cortex Axon agent connects to the Cortex service, authenticates, and registers itself with the integration type and alias name.
4. The agent starts an instance of the snyk-broker client process, and uses configuration details from the `/register` call (the registration in the previous step) to connect to the Cortex backend instance of the snyk-broker server.
5. Once this is established, API calls made on the Cortex side are relayed to the internal network, and the responses are relayed back to the Cortex service.

## How to use Cortex Axon Relay

Axon is composed of an agent which runs in a Docker container ([`cortex-axon-agent`](https://github.com/cortexapps/axon/pkgs/container/cortex-axon-agent)) and integrates with Kubernetes, creating a secure tunnel between the broker and Cortex.

### Prerequisites

Before getting started:

* Create an [API key](/configure/settings/api-keys#managing-api-keys-via-the-cortex-api) in Cortex.
* Create authentication credentials for the integration you're configuring.

### Step 1: Set up the Cortex Axon agent

#### Step 1.1: Configure the Relay in Cortex

{% hint style="info" %}
The Axon integration option can only be configured for [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), [Prometheus](/ingesting-data-into-cortex/integrations/prometheus), and [SonarQube](/ingesting-data-into-cortex/integrations/sonarqube).
{% endhint %}

1. In Cortex, click **Integrations**. Search for the integration you are setting up, then click **+Install**.

   <figure><img src="/files/jeUg87xrNIQ3BmARRYlB" alt=""><figcaption></figcaption></figure>
2. For the configuration type, select **Relay**.
3. In the side panel, enter an alias and configure any other necessary fields. At the bottom, click **Save**.

#### Step 1.2: Create a .env file and a docker-compose.yml file

1. Locally on your machine, create a file called `.env`. Inside the file, add contents for the integration you are configuring:

{% tabs %}
{% tab title="Docker Compose" %}
See the [variables for your integration in the README](https://github.com/cortexapps/axon/blob/main/README.relay.md#environment-variables-summary).

For example, for GitLab you would add:

```
CORTEX_API_TOKEN=your_cortex_token
GITLAB_TOKEN=your_gitlab_token
```

{% endtab %}

{% tab title="Kubernetes" %}
To run the agent in Kubernetes, you'll need to create a Deployment that runs the agent with similar configuration [as described above](#how-it-works).

There is a [Helm chart](https://github.com/cortexapps/axon/tree/main/examples/relay/helm-chart) available that can be used as a starting point. Its critical variables are:

```
# Example for github
relay:
  integration: github # can be blank
  subtype:   # optional, can be blank, see table above for options
  alias: alias for configuration from Cortex
  env:
    GITHUB: "https://github.com"
    GITHUB_API: "https://api.github.com"
    GITHUB_GRAPHQL_API: "https://api.github.com/graphql"
  verbose: false # set to true to enable verbose logging
```

If you have a proxy setup you can add values such as:

```
proxy:
  server:  http://proxy.example.com:8080
  noProxy: proxy.example.com # note localhost is added automatically
  certSecretName: my-proxy-ca-pem # name of the secret containing a .pem file with the CA certificate
```

{% endtab %}
{% endtabs %}

2. Locally on your machine, create a file called `docker-compose.yml`. Inside the file, add contents for the integration you are configuring:

{% tabs %}
{% tab title="GitHub" %}
**GitHub**:

```
services:
  axon:
    image: ghcr.io/cortexapps/cortex-axon-agent:latest
    env_file: .env
    env:
      - GITHUB_API=api.github.com
      - GITHUB_GRAPHQL=api.github.com/graphql
    command: [
      "relay",
      "-i", "github",
      "-a", "github-relay", # this is the alias you set up in the Cortex UI

      # if you are using a Github App token, add the following line
      # "-s", "app",
    ]
```

Additional environment variables include: `GITHUB_API=https://api.github.com`, `GITHUB_TOKEN`

**GitHub Hosted**:

```
services:
  axon:
    image: ghcr.io/cortexapps/cortex-axon-agent:latest
    env_file: .env
    env:
      - GITHUB_API=https://github.mycompany.com/api/v3
      - GITHUB_GRAPHQL=https://github.mycompany.com/api/graphql
    command: [
      "relay",
      "-i", "github",
      "-a", "github-relay", # this is the alias you set up in the Cortex UI

      # if you are using a Github App token, add the following line
      # "-s", "app",
    ]
```

Additional environment variables include: `GITHUB=https://github.mycompany.com`, `GITHUB_TOKEN`

**GitHub App**:

```
services:
  axon:
    image: ghcr.io/cortexapps/cortex-axon-agent:latest
    env_file: .env
    env:
      - GITHUB_API=https://api.github.com
      - GITHUB_GRAPHQL=https://api.github.com/graphql
    command: [
      "relay",
      "-i", "github",
      "-a", "github-relay", # this is the alias you set up in the Cortex UI

      # if you are using a Github App token, add the following line
      # "-s", "app",
    ]
```

Additional environment variables include: Arg `-s app`, `GITHUB=https://github.com`, `GITHUB_APP_CLIENT_ID`, `GITHUB_APP_CLIENT_PEM` (either path to PEM or PEM contents), `GITHUB_INSTALLATION_ID`
{% endtab %}

{% tab title="GitLab" %}

```
services:
  axon:
    image: ghcr.io/cortexapps/cortex-axon-agent:latest
    env_file: .env
    env:
      - GITLAB_API=https://gitlab.com
      - GITLAB_TOKEN=<token>
    command: [
      "relay",
      "-i", "gitlab",
      "-a", "gitlab-relay", # this is the alias you set up in the Cortex UI
    ]
```

{% endtab %}

{% tab title="Bitbucket" %}
**Bitbucket Cloud**:

```
    image: ghcr.io/cortexapps/cortex-axon-agent:latest
    env_file: .env
    env:
      - BITBUCKET_API=https://api.bitbucket.org
      - BITBUCKET_TOKEN=<token>
    command: [
      "relay",
      "-i", "bitbucket",
      "-a", "bibucket-relay", # this is the alias you set up in the Cortex UI
    ]
```

**Bitbucket Hosted**:

```
    image: ghcr.io/cortexapps/cortex-axon-agent:latest
    env_file: .env
    env:
      - BITBUCKET_API=https://bitbucket.mycompany.com
      - BITBUCKET_USERNAME=<user>
      - BITBUCKET_PASSWORD=<password>
    command: [
      "relay",
      "-i", "bitbucket",
      "-a", "bibucket-relay", # this is the alias you set up in the Cortex UI
    ]
```

{% endtab %}

{% tab title="Jira" %}
**Jira**:

```
    image: ghcr.io/cortexapps/cortex-axon-agent:latest
    env_file: .env
    env:
      - JIRA_API=https://jira.mycompany.com
      - JIRA_USERNAME:<user>
      - JIRA_TOKEN=<token>
    command: [
      "relay",
      "-i", "jira",
      "-a", "jira-relay", # this is the alias you set up in the Cortex UI
    ]
```

**Jira Bearer/Cloud**:

```
    image: ghcr.io/cortexapps/cortex-axon-agent:latest
    env_file: .env
    env:
      - JIRA_API=https://mycompany.atlassian.com
      - JIRA_TOKEN=<token>
    command: [
      "relay",
      "-i", "jira",
      "-a", "jira-relay", # this is the alias you set up in the Cortex UI
    ]
```

Additional variables include: Arg `-s bearer`
{% endtab %}

{% tab title="SonarQube" %}

```
    image: ghcr.io/cortexapps/cortex-axon-agent:latest
    env_file: .env
    env:
      - SONARQUBE_API=https://sonarqube.mycompany.com
      - SONARQUBE_TOKEN=<token>
    command: [
      "relay",
      "-i", "sonarqube",
      "-a", "sonarqube-relay", # this is the alias you set up in the Cortex UI
    ]
```

{% endtab %}

{% tab title="Prometheus" %}

```
    image: ghcr.io/cortexapps/cortex-axon-agent:latest
    env_file: .env
    env:
      - PROMETHEUS_API=http://mycompany.prometheus.internal
      - PROMETHEUS_USERNAME=<user>
      - PROMETHEUS_PASSWORD=<password>
    command: [
      "relay",
      "-i", "prometheus",
      "-a", "prometheus-relay", # this is the alias you set up in the Cortex UI
    ]
```

{% endtab %}
{% endtabs %}

### Step 2: Run the agent

#### Run the agent in a production environment

In a production environment, you will use a Helm chart, provided by Cortex.

#### Run the agent in a sandbox environment

1. In your CLI, run the command `docker compose up`.
   * You should see the agent start and connect to Cortex.
2. Verify that your agent is working:
   1. In Cortex, go to **Integrations** then navigate to your integration's settings page.
   2. Next to the Relay configuration you set up in the previous steps, click the play icon to test the integration.
      * If you watch the logging output in your CLI, you should see the agent receive the request and forward it to your internal service.
      * The page in Cortex should display a success message.

## Examples

See examples of using Axon with unsupported tools in the [Cortex Axon repository](https://github.com/cortexapps/axon/tree/main/examples).


# Apiiro

{% hint style="info" %}
Cortex connects to many third-party vendors whose system interfaces frequently change. As a result, integration behavior or configuration steps may shift without notice. If you encounter unexpected issues, check with your system administrator or refer to the vendor's documentation for the most current information. Additionally, integration sync times vary and are subject to scheduling overrides and timing variance.
{% endhint %}

[Apiiro](https://apiiro.com/) is an application security posture management (ASPM) platform that helps you understand and manage application security risks.

Integrating Apiiro with Cortex allows you to:

* [View risks on entity pages](#viewing-apiiro-risks-on-an-entity) in Cortex, quickly connecting issues to entities and their owners
* Use [Scorecards](#scorecards-and-cql) to drive quality improvements to your security practices relating to Apiiro applications, and set [Initiatives](/improve/initiatives) to prioritize tasks and set deadlines.

## How to configure Apiiro with Cortex

### Prerequisites

Before getting started:

* Create an [Apiiro API key](https://docs.apiiro.com/admin-apiiro/access-tokens). Include the following permissions:
  * `Risks > Read`
  * `Inventory management > Applications > Read`
  * `Inventory management > Repositories > Read`

### Configure the integration in Cortex

1. In Cortex, navigate to the [Apiiro settings page](https://app.getcortexapp.com/admin/integrations/apiiro).
   * Click **Integrations** from the main nav. Search for and select **Apiiro**.
2. Click **Add configuration**.
3. Configure the integration form:
   * **Alias**: Enter an alias for your configuration.
   * **API key**: Enter the API key you generated in Apiiro.
   * **Host**: Enter the base URL of your Apiiro instance. If left blank, the default host will be used.
4. Click **Save**.

After saving your configuration, you are redirected to the Apiiro integration settings page in Cortex. In the upper right corner of the page, click **Test configuration** to ensure Apiiro was configured properly.

## How to connect Cortex entities to Apiiro

### Discovery

Cortex uses the entity name, [Cortex tag](/ingesting-data-into-cortex/entities-overview/entities#cortex-tag), or repository as the "best guess" for the corresponding Apiiro application. For example, if your entity name is "My Service" or your tag is `my-service`, then the corresponding application name in Apiiro should also be My Service or `my-service`.

If your Apiiro application names don’t cleanly match the Cortex entity name or tag, you can override this in the Cortex entity descriptor.

### Editing the entity descriptor

You can define repositories and applications in the [entity descriptor](/ingesting-data-into-cortex/entities-overview/entities#defining-entities-via-yaml-file) under the `x-cortex-apiiro` block:

```yaml
x-cortex-apiiro:
  repositories:
    - alias: alias-one
      repositoryId: repository-one
    - alias: alias-two
      repositoryId: repository-two
  applications:
    - alias: alias-one
      applicationId: application-one
    - alias: alias-two
      applicationId: application-two
```

## Using the Apiiro integration

### Viewing Apiiro risks on an entity

#### Entity page overview

On an [entity details page](/ingesting-data-into-cortex/entities-overview/entities/details) overview, see risks listed under the **Code & security** block. Within this block, issues and vulnerabilities are grouped by severity: `Critical`, `High`, `Medium`, and `Low`. Click into any of these to open a list of all applicable issues and vulnerabilities.

#### Entity code & security sidebar

In an entity's sidebar, click **Code & security > Apiiro** to view risks from Apiiro.

### Scorecards and CQL

With the Apiiro integration, you can create Scorecard rules and write CQL queries based on Apiiro risks.

See more examples in the [CQL Explorer](https://app.getcortexapp.com/admin/cql-explorer) in Cortex.

<details>

<summary>List risks</summary>

List all risks for a given entity's Apiiro application.

**Definition**: `apiiro.risks()`

**Example**

A Scorecard's top level might include a rule to ensure that entities have a low number of Apiiro risks:

```
apiiro.risks().length < 3
```

</details>

<details>

<summary>Check if Apiiro application is set</summary>

Check if entity has a registered Apiiro application in its entity descriptor.

**Definition:** `apiiro ≠ null`

**Example**

An initial level in a security Scorecard might include a rule to make sure entities are associated with an Apiiro application. Without this, Cortex won't pick up data about applications in Apiiro:

```
apiiro != null
```

</details>

### View integration logs <a href="#still-need-help" id="still-need-help"></a>

{% hint style="info" %}
This feature is available in Cortex cloud.
{% endhint %}

While viewing an integration's settings page, select the **Logs** tab to view error logs from the last 7 days. You can filter the logs list by configuration and by operation (for example, you could filter to view errors surfaced only via Scorecards).

<div align="left" data-with-frame="true"><figure><img src="/files/x8JmoPqXZTJ7YHeFJpOA" alt="The &#x27;Logs&#x27; tab on an integration&#x27;s settings page shows error information over the past 7 days."><figcaption></figcaption></figure></div>

Click into a row to get more information, including time stamp, status code, full error, and request path.

## Still need help?[​](https://docs.cortex.io/docs/reference/integrations/aws#still-need-help) <a href="#still-need-help" id="still-need-help"></a>

The following options are available to get assistance from the Cortex Customer Engineering team:

* **Email**: <help@cortex.io>, or open a support ticket in the in app Resource Center
* **Slack**: Users with a connected Slack channel will have a workflow added to their account. From here, you can either @CortexTechnicalSupport or add a `:ticket:` reaction to a question in Slack, and the team will respond directly.

Don’t have a Slack channel? Talk with your Customer Success Manager.


# ArgoCD

{% hint style="info" %}
Cortex connects to many third-party vendors whose system interfaces frequently change. As a result, integration behavior or configuration steps may shift without notice. If you encounter unexpected issues, check with your system administrator or refer to the vendor's documentation for the most current information. Additionally, integration sync times vary and are subject to scheduling overrides and timing variance.
{% endhint %}

[ArgoCD](https://argoproj.github.io/cd/) is a declarative, GitOps continuous delivery tool for Kubernetes.

Integrating Cortex with ArgoCD allows you to:

* Send information about ArgoCD syncs into Cortex
  * This data appears on [entity detail pages](#view-argocd-data-on-entity-pages).
* Use [Cortex Workflows to automate ArgoCD syncs](#automate-argocd-events-in-workflows)
* See [deploy data for ArgoCD in Eng Intelligence](#see-argocd-data-in-eng-intelligence)

## How to configure ArgoCD with Cortex

### Step 1: Use ArgoCD notification webhooks

To send Cortex information about syncs in ArgoCD, use ArgoCD notification [Webhooks](https://argo-cd.readthedocs.io/en/stable/operator-manual/notifications/services/webhook/) to call the Cortex [deploy REST endpoint](/api/readme/deploys).

#### Example config map

Here is an example of what a `argocd-notifications-cm` config map may look like:

```yaml
apiVersion: v1
kind: ConfigMap
data:
  context: |
    argocdUrl: https://argo.company.com
  service.webhook.cortex-webhook: |
    url: https://api.getcortexapp.com
    headers:
    - name: Content-Type
      value: application/json
    - name: Accept
      value: application/json
    - name: Authorization
      value: Bearer $token 
    subscriptions: |
      - recipients:
        - cortex-webhook
        triggers:
        - on-sync-succeeded
  template.app-sync-succeeded: |
    webhook:
      cortex-webhook:
        method: POST
        path: /api/v1/catalog/{{.app.metadata.name}}/deploys 
        body: |
          { "customData": { "Sync Status": "{{.app.status.sync.status}}","Sync Details": "{{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true" },
            "environment": "{{.app.spec.destination.name}}",
            "sha": "{{.app.status.operationState.operation.sync.revision}}",
            "timestamp": "{{.app.status.operationState.finishedAt}}",
            "title": "Sync by ArgoCD",
            "type": "DEPLOY"
          }
  trigger.on-sync-succeeded: |
    - send:
      - app-sync-succeeded
      when: app.status.operationState.phase in ['Succeeded']
        
```

This example assumes your ArgoCD application's name matches the `x-cortex-tag`. In this case, each application in ArgoCD can subscribe to the same trigger.

If your application name doesn't match the `x-cortex-tag`, add a value/pair to the info section of the Application manifest. Then, instead of using `.app.metadata.name` in the url path, use `{{(index .app.spec.info 0).value}}`.

### Step 2: Subscribe application to webhooks

Next, subscribe your application to the webhook. You do this by adding a label annotation in the Application spec in the following format:

```yaml
    notifications.argoproj.io/subscribe.<trigger-name>.<webhook-name>: ""
```

For example, if we want to subscribe an application to the example webhook above, the Application YAML may look like the following example:

```yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  annotations:
    notifications.argoproj.io/subscribe.on-sync-succeeded.cortex-webhook: ""
...  

```

## Using the ArgoCD integration

### View ArgoCD data on entity pages

After you configure the integration, you will see data about ArgoCD syncs in an [entity's details page](/ingesting-data-into-cortex/entities-overview/entities/details):

* On the entity overview, ArgoCD syncs will appear under the **Latest events** section.\\

  <figure><img src="/files/gaKZMmMs7mfhiwqJCGI8" alt="ArgoCD syncs appear in the latest events on an entity."><figcaption></figcaption></figure>
* In the entity's sidebar, click **Events** to see a full list of events for the entity, including sync events from ArgoCD.
* In the entity's sidebar, click **CI/CD > Deploys** to see data from the [Cortex deploys API](/api/readme/deploys), including ArgoCD syncs.\\

  <div align="left"><figure><img src="/files/k6Eu2lT2RZFjrF9G8Xau" alt="ArgoCD data shows up on an entity page&#x27;s sidebar under CI/CD > Deploys." width="563"><figcaption></figcaption></figure></div>

### Automate ArgoCD events in Workflows

You can use a Workflow to automate ArgoCD syncs. See the [ArgoCD Workflow guide](/guides/operational-readiness/argocd-workflow) for more information.

### See ArgoCD data in Eng Intelligence

Since the ArgoCD integration uses Cortex's [deploys API endpoint](/api/readme/deploys), ArgoCD data is included in Eng Intelligence deploy metrics. Learn more about [Eng Intelligence in the docs](/improve/eng-intelligence).

## Troubleshooting and FAQ

#### What permissions does my API Key need?

The API key needs to be able to call the[ "Add deployment for entity"](https://docs.cortex.io/api/rest/deploys#post-api-v1-catalog-tagorid-deploys) API endpoint, so ensure the `Edit entities` permission is enabled.

#### Ensure the Cortex API Key is encoded correctly

Make sure the encoded Cortex API Key does not contain an extra line. Use a tool like <https://www.base64encode.org/> to ensure your encoded key does not contain an extra line.

#### Check the ArgoCD logs

The notification webhook is managed by the `argocd-notifications-controller` which will have a pod running in your ArgoCD namespace.

Assuming the ArgoCD is running in the `argocd` namepsace, run the following command to get the list of pods:

`kubectl get pods -n argocd`

This will return a list of pods similar to the ones listed below:

```
NAME                                                READY   STATUS    RESTARTS   AGE
argocd-application-controller-0                     1/1     Running   0          108d
argocd-applicationset-controller-69f96ccf5b-5jnpv   1/1     Running   0          108d
argocd-dex-server-5dff9c5998-j29zd                  1/1     Running   0          80d
argocd-notifications-controller-6cd988b564-sql55    1/1     Running   0          107d
argocd-redis-54c687db9d-kdxwj                       1/1     Running   0          80d
argocd-repo-server-6c6f8859c7-mrwll                 1/1     Running   0          108d
argocd-server-b77b48886-s2mtg                       1/1     Running   0          80d
```

In this example, the pod managing the webhook notifications is `argocd-notifications-controller-6cd988b564-sql55`. To get the logs, run the following command:

`kubectl logs argocd-notifications-controller-6cd988b564-sql55 -n argocd`

If your trigger was successful, you should seem something similar to this:

```
time="2023-07-19T02:41:13Z" level=info msg="Start processing" app=argocd/app-direct
time="2023-07-19T02:41:13Z" level=info msg="Trigger on-sync-succeeded result: []" app=argocd/app-direct
time="2023-07-19T02:41:13Z" level=info msg="Notification about condition 'on-sync-succeeded.[0].zxM90Et6k4Elb1-fHdjtDJq0xR0' already sent to ''" app=argocd/app-direct
time="2023-07-19T02:41:13Z" level=info msg="Processing completed" app=argocd/app-direct
```

## Still need help?[​](https://docs.cortex.io/docs/reference/integrations/aws#still-need-help) <a href="#still-need-help" id="still-need-help"></a>

The following options are available to get assistance from the Cortex Customer Engineering team:

* **Email**: <help@cortex.io>, or open a support ticket in the in app Resource Center
* **Slack**: Users with a connected Slack channel will have a workflow added to their account. From here, you can either @CortexTechnicalSupport or add a `:ticket:` reaction to a question in Slack, and the team will respond directly.

Don’t have a Slack channel? Talk with your Customer Success Manager.


# AWS

Configuring the integration for AWS

{% hint style="info" %}
Cortex connects to many third-party vendors whose system interfaces frequently change. As a result, integration behavior or configuration steps may shift without notice. If you encounter unexpected issues, check with your system administrator or refer to the vendor's documentation for the most current information. Additionally, integration sync times vary and are subject to scheduling overrides and timing variance.
{% endhint %}

## Why use the integration for AWS

Amazon Web Services (AWS) provides on-demand cloud computing platforms and APIs.

As your AWS footprint grows across accounts, regions, and resource types, it gets harder to answer simple questions: what resources exist, who owns them, and how they connect to the services your teams run day to day. Integrating Cortex with AWS gives you a live, accurate picture of your AWS environment, so that information doesn't live only in the AWS console, or in a spreadsheet someone updates once a quarter.

When you connect AWS to Cortex, you get:

* A single catalog of your AWS resources that stays in sync automatically, instead of one you maintain by hand.
* Clear [ownership](/ingesting-data-into-cortex/integrations/aws/importing-entities-from-aws#ownership-and-dependencies-for-aws-entities), discovered from the tags you already use, so you can find who's responsible for a resource without asking around.
* Dependency mapping between your services and the AWS resources they rely on, so you can see the blast radius of a change before you make it.
* [Scorecards and CQL queries](/ingesting-data-into-cortex/integrations/aws/using-the-integration-for-aws#scorecards-and-cql) that measure your AWS resources against standards like tagging hygiene, deprecated runtimes, or required configurations.
* A [discovery audit](/ingesting-data-into-cortex/integrations/aws/importing-entities-from-aws#discovery-audit) that flags new or missing AWS resources, so your catalog doesn't quietly drift out of date.

If you are on a self-hosted Cortex instance, see the [self-managed AWS](/self-managed/features/integrations/aws) setup instructions.

## Configuring AWS

### Prerequisites

1. Users with the `Configure Integrations` permission can configure AWS.

### Step 1: Configuring the integration in Cortex

1. From the main sidebar, select **Integrations**.
2. Locate AWS, then click **Install**. The AWS side panel opens.
3. In the modal, the JSON configuration, Cortex AWS account ID, and External ID are displayed. In the configuration side bar instructions, you will also see the option to copy a starting "Read Only Access" JSON policy. Keep this browser window open, as you will need these in the next steps.

### Step 2: Configuring an IAM policy in AWS

You must configure an IAM policy for each account you want to connect to Cortex.

{% hint style="info" %}
When using Cloud Control, the role Cortex assumes to get access into your account needs to have read access to all the selected types. This access is included by default in the Read Only Access policy in Cortex, or it can be configured manually for each type.
{% endhint %}

1. Log in to the AWS Management Console, then open the [IAM console](https://console.aws.amazon.com/iam/).
2. Click **Policies**, then choose **Create policy**.
3. Switch to the JSON editor. In Cortex while configuring AWS, copy the JSON "Read Only Access" starting policy that appears in the in-app instructions. Paste it into the JSON editor.
   * This policy allows Cortex to list all resources, resource types, and resource tags.
   * If you choose to configure this manually, rather than using the starting policy provided, insert a valid IAM policy depending on the resource types you'd like to import. For example, if you want to import resources of type `AWS::IAM::role`, we'll need to have permission to `iam:ListRoles`, `iam:ListAttachedRolePolicies`, `iam:GetRole`, `iam:ListAccountAliases` and `iam:ListRolePolicies`.
     * For manual configurations, make sure to add the `cloudformation:ListTypes`, `cloudformation:ListResources`, and `cloudformation:GetResource` permissions so that we can pull the list of types available from AWS.
4. Click **Review Policy**, enter a name, then click **Create Policy**.

See the AWS documentation for more information: [Create IAM policies](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_create-console.html).

### Step 3: Create a role in AWS

This section is specific to cloud-based Cortex accounts. If you are on a self-hosted Cortex instance, please see the AWS account setup guide for self-hosted Cortex.

1. In AWS, navigate to **Roles > Create Role**.
2. For the trusted entity type, select **Another AWS account**.
3. In the **Account ID** field, enter the Cortex AWS account ID that was displayed in Cortex in the earlier steps.
4. Click **Require External ID**, then enter the Cortex external ID that was displayed in Cortex in the earlier steps.
5. Click **Next**.
6. Select your newly created policy, and click **Next**.
7. Enter a name for your role. Optionally, configure tags. When you are finished, click **Create Role**.
8. Search for your new role in the list and copy its name. You will need this in the next steps.
9. In the upper right corner of AWS, click your name. In the dropdown that appears, copy your AWS account ID. You will need these in the next steps.

Note that if you use multiple AWS accounts, they will share a common rotatable `externalId`.

### Step 4: Finish the configuration in Cortex

1. Navigate back to the browser window containing your [Cortex AWS settings page](https://app.getcortexapp.com/admin/settings/aws).
2. Configure the AWS integration form:
   * **Account ID**: Enter the AWS account ID you obtained in the previous steps.
   * **IAM role**: Enter the role name you obtained in the previous steps.
3. Click **Save**.


# Importing entities from AWS

Automatically import AWS resources as entities, discover dependencies between them, and keep ownership in sync

{% hint style="info" %}
Cortex connects to many third-party vendors whose system interfaces frequently change. As a result, integration behavior or configuration steps may shift without notice. If you encounter unexpected issues, check with your system administrator or refer to the vendor's documentation for the most current information. Additionally, integration sync times vary and are subject to scheduling overrides and timing variance.
{% endhint %}

This article explains how to import entities from AWS. For configuration instructions, see [Configuring the integration for AWS](/ingesting-data-into-cortex/integrations/aws). For instructions on using the integration, see [Using the integration for AWS](/ingesting-data-into-cortex/integrations/aws/using-the-integration-for-aws).

### Keep in mind

When importing from AWS, Cortex replaces non-alphanumeric characters in entity names with a space. For example, `resource_1` becomes `resource 1`.

For the [Cortex tag](/ingesting-data-into-cortex/entities-overview/entities#cortex-tag), Cortex replaces non-alphanumeric characters with `-` and lowercases the letters. If multiple special characters appear together in a tag, Cortex replaces the group of characters with only one `-`. For example, `mY_e%ntity#$_tag` becomes `my-e-ntity-tag`.

## Importing an entity from AWS

Cortex gives you two ways to import entities from AWS: automatically or manually.

Turn on auto import and Cortex creates an entity for every resource it discovers in the Cloud Control types you've selected, then keeps them in sync as your AWS environment changes.&#x20;

Import manually instead if you'd rather pick exactly which discovered resources land in your catalog and set details like ownership and repository as you go.&#x20;

If an entity already exists in Cortex, you can connect it to specific AWS resources by adding an `x-cortex-infra` block to its YAML.

### Prerequisites

1. Ensure that Cortex only pulls the cloud control types you want it to:
   1. From the main sidebar, select **Integrations**.
   2. Locate AWS, then click **Settings**.
   3. Select the **Integration settings** tab.
   4. From the **Cloud control types** dropdown, select the types you want Cortex to discover.
      * When you turn on auto-import for AWS, Cortex imports these types automatically.
      * To remove an auto-imported cloud control type, click the **X** next to its name, then click **Save cloud control types**.
   5. Click **Save cloud control types**.

{% hint style="warning" %}
If a type does not appear in the list, ensure that `cloudformation:ListTypes`, `cloudformation:ListResources`, and `cloudformation:GetResource` are added to your IAM policy.
{% endhint %}

<details>

<summary>The following cloud control types are NOT supported</summary>

```
AWS::ApiGateway::DocumentationVersion
AWS::ApiGateway::Step
AWS::CloudFormation::ResourceVersion
AWS::CustomerProfiles::Integration
AWS::CustomerProfiles::ObjectType
AWS::EC2::TransitGatewayMulticastGroupMember
AWS::EC2::TransitGatewayMulticastGroupSource
AWS::ECS::TaskSet
AWS::Glue::Attach::SchemaVersion
AWS::Glue::Attach::SchemaVersionMetadata
AWS::IoTSiteWise::AccessPolicy
AWS::IoTSiteWise::Dashboard
AWS::IoTSiteWise::Project
AWS::Kendra::DataSource
AWS::Kendra::Faq
AWS::MediaConnect::FlowEntitlement
AWS::MediaConnect::FlowOutput
AWS::MediaConnect::FlowSource
AWS::MediaConnect::FlowVpcInterface
AWS::MediaPackage::Asset
AWS::MediaPackage::PackagingConfiguration
AWS::NetworkFirewall::LoggingConfiguration
AWS::QuickSight::Analysis
AWS::QuickSight::Dashboard
AWS::QuickSight::DataSet
AWS::QuickSight::DataSource
AWS::QuickSight::Template
AWS::QuickSight::Theme
AWS::RDS::DBProxyTargetGroup
AWS::S3Outposts::AccessPoint
AWS::S3Outposts::Bucket
AWS::SSO::Assignment
AWS::SSO::InstanceAccessControlAttributeConfiguration
AWS::SSO::PermissionSet
```

If the type you want to import is in the list above, contact <support@cortex.io> to submit a feature request.

</details>

### Automatically importing AWS entities

Users with the `Manage Integrations` permission can enable auto import of AWS resources.

Follow the steps below to configure automatic import from AWS. If you don't want Cortex to auto import AWS resources, you can [manually import them](#manually-importing-aws-services-via-entity-descriptor).

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 **General**.
5. Under **Entity settings**, toggle on **Auto import from AWS, Azure, and/or Google Cloud**.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/qgP1zaZFbXpttIQuTd7G" alt="The auto import option toggled on in the Settings." width="563"><figcaption></figcaption></figure></div>

After you toggle on auto-import, Cortex imports all entities of the selected types into your catalog, and keeps importing new ones as it discovers them.

#### Limiting discovery to specific regions

By default, Cortex searches for resources across all AWS regions, but you can limit that to specific regions.

1. From the main sidebar, select **Integrations**.
2. Locate AWS, then click **Settings**.
3. Select the **Integration settings** tab.
4. Scroll to **Regions**, then select one or more regions from the dropdown. <br>

   <div align="left" data-with-frame="true"><figure><img src="/files/EyBJjx0QWsri93co6mcT" alt="The &#x27;Regions&#x27; dropdown." width="375"><figcaption></figcaption></figure></div>
5. Click **Save regions**. Cortex will now only search across the regions you specified.

### Manually importing AWS entities

Follow the steps below to manually import from AWS. If you don't want to import manually, you can [automatically import them](#automatically-importing-aws-entities).

1. From the main sidebar, expand **Catalogs**, then select **All entities**.
2. In the upper-right corner, click **Import entities**.
3. Select **Import discovered entities**.
4. Select AWS. The **Select entities to import** page is displayed.
5. A list of entities is displayed. Select the checkboxes next to the entities you want to import. Use the search bar to find entities by name, or click the **Filter icon** in the upper-right corner of the results list to filter by entity type.
6. In the bottom-right corner, click **Next step**. The **Edit details** page is displayed.
7. Configure the following:
   1. From the **Type** drop-down menu, select **Service.**
   2. In the **Details** sectio&#x6E;**:**
      1. Under **Entity name**, enter a name for the entity (required).
      2. The **Cortex tag** field is auto-populated based on the name of the entity (required). It's a unique identifier for the entity. This is also known as the `x-cortex-tag`.
      3. Under **Description**, enter a description of the entity to help others understand its purpose.
      4. From the **Groups** drop-down men&#x75;**,** select a group or groups [to segment the entity](https://docs.cortex.io/ingesting-data-into-cortex/entities-overview/entities/groups).
   3. In the **Repository** section:
      1. From the **Provider** drop-down menu, select the repo provider.
      2. From the **Alias** drop-down menu, select the alias of the connected provider account that has access to the repository.
      3. From the **Repository** drop-down menu, select the repo associated with the entity. If you don't see it listed, click **Refresh repositories** to pull in the latest list.
      4. Under **Basepath**, enter the subdirectory within the repo where the entity's code lives. Leave blank if the entity occupies the entire repo.
   4. In the **Owners** section, define [ownership](https://docs.cortex.io/ingesting-data-into-cortex/entities-overview/entities/ownership) for the entity. Ownership can be assigned to either teams or individual users. It's recommended to select team owners to keep the ownership information up to date through any future personnel changes. To add a team or teams, click **Add** in the **Teams** area. To add an individual user or users, click **Add** in the **Users** area.
      * Cortex may recommend owners [based on repository activity](https://docs.cortex.io/ingesting-data-into-cortex/entities-overview/entities/ownership#recommendation). You can accept or reject the recommendations.
   5. In the **Links** section, click **Add** to add links to external documentation, such as runbooks, docs, logs, or custom categories.
   6. In the **Slack channels** section, click **Add** to link a Slack channel to the entity. If enabled, you'll receive notifications about the entity in the selected Slack channel.
   7. In the **Parents** section, select a parent domain or domains from the drop-down menu. This is where you configure the hierarchy for your entity, which can be visualized in the [relationship graph](https://docs.cortex.io/ingesting-data-into-cortex/entities-overview/entities/relationship-graph).
   8. In the **Dependencies** section, click **Add entity** to select an entity or entities that this entity depends on. These can be visualized in the [relationship graph](https://docs.cortex.io/ingesting-data-into-cortex/entities-overview/entities/relationship-graph).
8. If you selected more than one entity, click **Next entity** in the bottom-right corner of the page.
9. Click **Confirm import**. The entity is imported into Cortex.

### Editing an entity via its descriptor

To connect a Cortex entity to one or more AWS resources, add the `x-cortex-infra` block to the entity's YAML. For certain AWS resource types, Cortex displays those AWS entities' metadata on the Cortex entity page.

<table><thead><tr><th width="147.14453125">Field</th><th width="445.19140625">Description</th><th align="center">Required?</th></tr></thead><tbody><tr><td><code>type</code></td><td>The AWS Cloud Control resource type, e.g. <code>AWS::RDS::DBInstance</code></td><td align="center"><i class="fa-check">:check:</i></td></tr><tr><td><code>region</code></td><td>The AWS region the resource belongs to</td><td align="center"><i class="fa-check">:check:</i></td></tr><tr><td><code>accountId</code></td><td>The AWS account ID the resource belongs to</td><td align="center"><i class="fa-check">:check:</i></td></tr><tr><td><code>identifier</code></td><td>The primary identifier of the resource</td><td align="center"><i class="fa-check">:check:</i></td></tr></tbody></table>

**Example**

```yaml
x-cortex-infra:
  aws:
    cloudControl:
    - type: AWS::RDS::DBInstance
      region: us-west-2
      accountId: "623456123456"
      identifier: checkout-db-prod
```

#### Connecting multiple ECS services to a single entity

To connect a Cortex entity to multiple ECS services, use one of the formats below, depending on whether you're using Cloud Control resource types.

<table><thead><tr><th width="147.14453125">Field</th><th width="445.19140625">Description</th><th align="center">Required?</th></tr></thead><tbody><tr><td><code>type</code></td><td>Must be <code>AWS::ECS::Service</code></td><td align="center"><i class="fa-check">:check:</i></td></tr><tr><td><code>region</code></td><td>The AWS region the service belongs to</td><td align="center"><i class="fa-check">:check:</i></td></tr><tr><td><code>accountId</code></td><td>The AWS account ID the service belongs to</td><td align="center"><i class="fa-check">:check:</i></td></tr><tr><td><code>identifier</code></td><td>The primary identifier of the service</td><td align="center"><i class="fa-check">:check:</i></td></tr></tbody></table>

**Example**

```yaml
x-cortex-infra:
  aws:
    cloudControl:
    - type: AWS::ECS::Service
      region: us-west-2
      accountId: "623456123456"
      identifier: checkout-service
    - type: AWS::ECS::Service
      region: us-east-1
      accountId: "345673456731"
      identifier: checkout-service-dr
```

#### Using the legacy ECS format

If you're not using Cloud Control types, or you imported your entity before Cortex supported Cloud Control types, use the format below.

<table><thead><tr><th width="147.14453125">Field</th><th width="445.19140625">Description</th><th align="center">Required?</th></tr></thead><tbody><tr><td><code>clusterArn</code></td><td>The ECS cluster's ARN. See <a href="https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html">ECS</a> for details.</td><td align="center"><i class="fa-check">:check:</i></td></tr><tr><td><code>serviceArn</code></td><td>The ECS service's ARN. See <a href="https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html">ECS</a> for details.</td><td align="center"><i class="fa-check">:check:</i></td></tr></tbody></table>

**Example**

```yaml
x-cortex-infra:
  aws:
    ecs:
      - clusterArn: arn:aws:ecs:us-west-2:123456789012:cluster/checkout-cluster
        serviceArn: arn:aws:ecs:us-west-2:123456789012:service/checkout-cluster/checkout-service
      - clusterArn: arn:aws:ecs:us-east-1:123456789012:cluster/checkout-cluster-dr
        serviceArn: arn:aws:ecs:us-east-1:123456789012:service/checkout-cluster-dr/checkout-service-dr
```

### Discovery audit

Cortex pulls recent changes from your AWS environment into the [discovered entities list](/ingesting-data-into-cortex/entities-overview/entities/discovery-audit), where you can find:

* New entities in AWS that haven't been imported into your Cortex catalog. These are tagged **New AWS Resource**.
* Entities in the catalog that no longer exist in AWS. These are tagged **AWS Resource Not Detected**.

<div align="left" data-with-frame="true"><figure><img src="/files/Jrr2jEQ4hLtP90aG6nJ1" alt="The &#x27;Discovered entities&#x27; list." width="563"><figcaption></figcaption></figure></div>

## Relationships, ownership, and dependencies for AWS entities

### **Configuring tag-based auto-linking for AWS**

You can configure any relationship type to automatically create relationships between AWS resources and other Cortex entities based on matching AWS tag values. This is the recommended way to connect AWS resources to domains, services, or custom entities for Scorecard reporting.

{% hint style="info" %}
The **Auto-create relationships from integration tags** section only appears when at least one AWS-backed entity type is selected as the source and/or destination.
{% endhint %}

**To configure tag-based auto-linking**:

1. From the main sidebar, expand **Catalogs**, then select **All entities**.
2. Select the **Relationship types** tab.
3. Locate the relationship type you want to configure, then click the **pencil icon**. You can also create a new relationship type.
4. Scroll to the **Auto-create relationships from integration tags** section.
5. From the **Provider** drop-down menu, select **AWS**.
6. Configure the **Source tag key** by doing one of the following:
   * Enter the AWS tag key on the source entity (e.g. `cortex-entity-tag`), OR
   * Toggle on **Cortex provided tag** to use Cortex's standardized managed tag key.
7. Configure the **Destination tag key** by doing one of the following:
   * Enter the tag key on the destination entity (e.g. `AWS-tag-parent`), OR
   * Toggle on **Cortex provided tag** to use Cortex's standardized managed tag key.
8. Click **Save** (or **Create** if it's a new relationship type).

{% hint style="info" %}
Once a relationship type is saved with integration-backed auto-creation configured, this setting cannot be changed. To modify it, delete the relationship type and create a new one.
{% endhint %}

Cortex scans entities matching the relationship type's source and destination definitions and creates a relationship wherever tag values match. Newly configured relationships are created asynchronously and may take up to one sync cycle to appear.

**Example: Linking AWS resources to domains**

To roll AWS resources up to a domain for Scorecard reporting:

1. Tag your AWS resources with the domain they belong to (e.g. a `domain` tag with the domain's Cortex tag as the value).
2. Create or open a relationship type with AWS resources as the source and domains as the destination.
3. In the **Auto-create relationships from integration tags** section, set the source tag key to `domain` and the destination tag key to the corresponding identifier on your domain entities.
4. Click **Save**. Cortex creates the relationships automatically.

### Discovering dependencies automatically

Cortex automatically discovers dependencies between your services and resources by scanning for AWS resources tagged with specific keys. By default, a service depends on any Cortex resource whose corresponding AWS resource has a tag where the key is `service` and the value matches the service's Cortex tag.

{% hint style="info" %}
Cortex syncs AWS tags (dependencies) daily at 8 a.m. UTC.&#x20;

**To manually refresh tags**:

1. From the main sidebar, expand Tools, then select **Relationship graphs**.
2. In the upper-right corner, click the **overflow menu icon**, then select **Sync dependencies**.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/E3UDZUeLW5TSIPRt2LrY" alt="The &#x27;Sync dependencies&#x27; option." width="131"><figcaption></figcaption></figure></div>

{% endhint %}

Specifying a tag name is optional. If you don't specify one, Cortex uses `service` as the key name.

**To specify a tag name in Cortex**:

1. From the main sidebar, select **Integrations**.
2. Locate AWS, then click **Settings**.
3. Select the **Integration settings** tab.
4. Scroll to **Dependencies sync from AWS**, then select one or more tags from the dropdown. Note that an `AND` operator is used when you select multiple tags; the resource needs to have all specified tags in order to be recognized by Cortex.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/pmQ39Y1K5INgAQRHaGao" alt="The &#x27;Dependencies sync from AWS&#x27; section." width="375"><figcaption></figcaption></figure></div>
5. Click **Save dependency tag keys**.

#### **Using key/value pairs in the entity descriptor for dependency discovery**

You can also define explicit tag key/value pairs in the `x-cortex-dependency` block for AWS dependency discovery. Instead of matching on service tags, Cortex matches a service to any AWS resource whose tags match the key/value pairs you define in the service's `x-cortex-dependency` block.&#x20;

For example, the service below depends on any AWS resource tagged with key `service` and value `checkout-service`, key `team` and value `checkout-team`, or a resource created by the CloudFormation stack `checkout-service-prod`.

```yaml
x-cortex-dependency:
  aws:
    tags:
      - key: service
        value: checkout-service
      - key: team
        value: checkout-team
      - key: "aws:cloudformation:stack-name"
        value: "checkout-service-prod"
      - key: "aws:cloudformation:stack-id"
        value: "arn:aws:cloudformation:us-west-2:123456789012:stack/checkout-service-prod/1a2b3c4d-5e6f-4a1b-8c9d-0e1f2a3b4c5d"
```

For more information, see the [Dependencies documentation](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/dependencies).

### **Auto-creating AWS account entities**

Users with the `Manage Integrations` permission can configure the auto-creation of AWS account entities.

When enabled, Cortex automatically creates an entity for each AWS account connected to your integration and links it to its AWS resources through a built-in, Cortex-managed relationship.&#x20;

{% hint style="info" %}
The **Auto import from AWS, Azure, and/or Google Cloud** setting must be [toggled on](#automatically-importing-aws-entities) prior to auto-creating AWS account entities.
{% endhint %}

**To enable AWS account auto-creation:**

1. From the main sidebar, select **Integrations**.
2. Locate AWS, then click **Settings**.
3. Select the **Integration settings** tab.
4. Scroll to **Accounts as entities**, then toggle on **Import AWS accounts as entities**.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/niDeXtqssgYuOtvkv2LH" alt="The &#x27;Import AWS accounts as entities&#x27; option in the AWS settings." width="375"><figcaption></figcaption></figure></div>

Once enabled:

* Cortex creates an **AWS Account** entity for each account configured in Cortex.
* Each AWS resource is automatically linked to its parent account through a Cortex-managed relationship.

As new accounts are configured and resources are discovered, entities and relationships stay in sync automatically.

**To view your AWS account entities:**

1. From the main sidebar, expand **Catalogs**.
2. Select **All entities**, then select the **Entity types** tab.
3. Search for **AWS account**.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/M2mIug0htgr4ENDksTeN" alt="The search box on the &#x27;Entity types&#x27; page." width="563"><figcaption></figcaption></figure></div>
4. Select an entity type, then select an entity.
5. From the **Catalog** menu, select the **Relationships** tab.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/fPHV2WcqdxsWQLboASK5" alt="The &#x27;Relationships&#x27; tab." width="375"><figcaption></figcaption></figure></div>

### Discovering ownership for AWS

Cortex can automatically discover ownership for your AWS resources. By default, Cortex looks for the `owner` tag, but you can customize the tag key name.

{% hint style="info" %}
Cortex syncs ownership from AWS daily at 6 a.m. UTC.
{% endhint %}

1. From the main sidebar, select **Integrations**.
2. Locate AWS, then click **Settings**.
3. Select the **Integration settings** tab.
4. Scroll to **Ownership sync from AWS**, then toggle on **Enable ownership sync**.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/Q3PMQGS4GCwLZoH6pPDK" alt="The &#x27;Ownership sync from AWS&#x27; section." width="375"><figcaption></figcaption></figure></div>
5. Optionally, customize the tag key name:
   1. From the **Select tags** dropdown, select one or more tags.
   2. Click **Save ownership tag keys**.

####


# Using the integration for AWS

How to use the integration for AWS in Cortex

{% hint style="info" %}
Cortex connects to many third-party vendors whose system interfaces frequently change. As a result, integration behavior or configuration steps may shift without notice. If you encounter unexpected issues, check with your system administrator or refer to the vendor's documentation for the most current information. Additionally, integration sync times vary and are subject to scheduling overrides and timing variance.
{% endhint %}

This article explains how to use the integration for AWS. For configuration instructions, see [Configuring the integration for AWS](/ingesting-data-into-cortex/integrations/aws). For instructions on connecting GCP to entities, see [Connecting entities to AWS](/ingesting-data-into-cortex/integrations/aws/importing-entities-from-aws).

{% hint style="info" %}
Cortex conducts a sync of integration details daily at 10 a.m. UTC.
{% endhint %}

## Viewing AWS data on an entity

The **Cloud > AWS** section of an entity's details sidebar shows Amazon Elastic Container Service (ECS) data for the ECS services linked to that entity.

Only ECS services populate this section. Cortex reads the entity's `x-cortex-infra` block, keeps any entries of type `AWS::ECS::Service`, and builds the view from those:

```yaml
x-cortex-infra:
  aws:
    cloudControl:
    - type: AWS::ECS::Service
      region: us-west-2
      accountId: "123456123456"
      identifier: arn:aws:ecs:us-west-2:123456123456:service/payments-cluster/payments-api
```

<table><thead><tr><th width="147.55078125">Field</th><th width="448.7578125">Description</th><th align="center">Required</th></tr></thead><tbody><tr><td><code>type</code></td><td>The AWS Cloud Control resource type. Only <code>AWS::ECS::Service</code> populates the <strong>Cloud > AWS</strong> section.</td><td align="center"><i class="fa-check">:check:</i></td></tr><tr><td><code>region</code></td><td>The AWS region the ECS service runs in, for example <code>us-west-2</code>.</td><td align="center"><i class="fa-check">:check:</i></td></tr><tr><td><code>accountId</code></td><td>The ID of the AWS account that owns the service. Wrap the value in quotation marks so leading zeros aren't dropped.</td><td align="center"><i class="fa-check">:check:</i></td></tr><tr><td><code>identifier</code></td><td>The fully-qualified ARN of the ECS service.<br><br>Note that the <code>identifier</code> must be the fully-qualified ARN of the ECS service, not the service name.</td><td align="center"><i class="fa-check">:check:</i></td></tr></tbody></table>

A few things to keep in mind:

* `AWS::ECS::Service` is the only type that populates this section. Other AWS types, including `AWS::ECS::Cluster`, don't populate it, even when they're linked to the entity correctly.
* Links defined with `x-cortex-relationships` don't populate this section. To see data here, link the ECS service in the entity's `x-cortex-infra` block.
* If an entity has no linked ECS service, the **Cloud > AWS** section doesn't appear in its details sidebar.

To work with other AWS resource types in Cortex, [import them as entities](/ingesting-data-into-cortex/integrations/aws/importing-entities-from-aws#connecting-an-entity-to-aws), then connect them to related entities using [relationships](/ingesting-data-into-cortex/entities-overview/entities/defining-relationship-types). You can also query their metadata with the `aws.details()` function in [CQL](/ingesting-data-into-cortex/integrations/aws/using-the-integration-for-aws#scorecards-and-cql).

## Searching AWS entities in Cortex

The following keys are supported when searching for your AWS entities in Cortex.

* `aws-account-id` - Account ID number
* `aws-account-name` - Account alias
* `aws-region` - AWS region of the resource
* `aws-type` - AWS type of the resource
* `aws-name` - AWS name of the resource
* `aws-identifier` - The primary identifier of a resource
* `aws-secondary-identifier` - The secondary identifier of a resource
* `aws-arn` - Searches for an Amazon Resource Name (ARN). This is not supported for Cloud Control types.

**To search for entities**:

1. From the main sidebar, expand **Catalogs**, then select **All entities**.
2. Do one of the following:
   * Select the **All** tab to search and filter across all of your organization's entities.
   * Select the **Mine** tab to search and filter only the entities you own.
   * Note that Cortex saves your selection and restores it the next time you open this page.
3. In the upper-right corner, enter your search parameters in the Search bar.&#x20;

### Example search queries

* `aws-type:"AWS::EC2" AND aws-region:"us-west"` - Searches for entities of category EC2 in the any of us-west regions
* `aws-account-id: "234512324"` - Searches for all entities from the account 234512324
* `aws-name:"aws-identifier-of-resource" AND aws-account-name:"test-account"` - Searches for entities with the identifier `aws-identifier-of-resource` in the account with alias `test-account`

## Scorecards and CQL

With the AWS integration, you can create Scorecard rules and write CQL queries based on AWS resources.

See more examples in the [CQL Explorer](https://app.getcortexapp.com/admin/cql-explorer) in Cortex.

<details>

<summary>AWS details</summary>

Get the AWS details for an entity

**Definition** - `aws.details(): Object`

**Example**

In a Scorecard, you can create a rule to verify that an entity of type `lamda` has a correct function name:

```
aws.details().resources.filter((resource) => resource.typeName == "AWS::Lambda::Function").length > 0
```

You could also create a rule to verify that an entity is not using deprecated runtimes:

```
aws.details().resources.filter((resource) => resource.typeName == "AWS::Lambda::Function" and resource?.metadata?.get("Runtime")?.matchesIn("(python3\\.6|python2\\.7|dotnetcore2\\.1|ruby2\\.5|nodejs12\\.|nodejs10\\.|nodejs8\\.10|nodejs4\\.3|nodejs6\\.10|dotnetcore1\\.0|dotnetcore2\\.0|nodejs4\\.3-edge|nodejs$)")).length == 0    
```

</details>

## Viewing AWS integration logs <a href="#still-need-help" id="still-need-help"></a>

{% hint style="info" %}
This feature is available in Cortex cloud.
{% endhint %}

While viewing an integration's settings page, select the **Logs** tab to view error logs from the last 7 days. You can filter the logs list by configuration and by operation (for example, you could filter to view errors surfaced only via Scorecards).

<div align="left" data-with-frame="true"><figure><img src="/files/x8JmoPqXZTJ7YHeFJpOA" alt="The &#x27;Logs&#x27; tab on an integration&#x27;s settings page shows error information over the past 7 days."><figcaption></figcaption></figure></div>

Click into a row to get more information, including time stamp, status code, full error, and request path.

## Troubleshooting and FAQ <a href="#still-need-help" id="still-need-help"></a>

See frequently asked questions below.

**If I have auto-import enabled, how can I remove cloud control types that I no longer want to be imported?**

If you want to remove any of the cloud control types after importing them: Disable the [automatic import](#enable-automatic-import-of-aws-entities) setting, remove the cloud control types from your [AWS integration settings](#step-5-select-aws-resource-types), then enable [auto-archival](/ingesting-data-into-cortex/entities-overview/entities/archiving-entities/auto-archive). This will cause the removed cloud control types to be archived during the next sync.

**Why am I seeing the AWS account ID instead of the AWS account alias?**

We've recently added support for pulling in the AWS account alias. The required permission is `iam:ListAccountAliases` (see the AWS documentation [here](https://000001.awsstudygroup.com/1-create-new-aws-account/1.3-aws-account-alias/#create-or-edit-an-account-alias)). Once this permission is added, the we will persist the account alias everywhere instead of the ID.

**Why don't I see the Cloud > AWS section on an entity?**

That section only appears on entities that have an `AWS::ECS::Service` resource linked in their `x-cortex-infra` block. If the entity has no linked ECS service, or is linked to a different AWS type such as `AWS::ECS::Cluster`, Cortex hides the section instead of showing an empty page. See [Viewing AWS data on an entity](#viewing-aws-data-on-an-entity).

**When does Cortex sync AWS resources?**

Cortex conducts the following daily syncs for AWS:

* Integration details daily at 10 a.m. UTC
* Ownership sync daily at 6 a.m. UTC
* AWS tag sync (dependencies) daily at 8 a.m. UTC

  * This sync can also be [triggered manually](/ingesting-data-into-cortex/integrations/aws/importing-entities-from-aws#discovering-dependencies-automatically)

  <br>


# Azure DevOps

{% hint style="info" %}
Cortex connects to many third-party vendors whose system interfaces frequently change. As a result, integration behavior or configuration steps may shift without notice. If you encounter unexpected issues, check with your system administrator or refer to the vendor's documentation for the most current information. Additionally, integration sync times vary and are subject to scheduling overrides and timing variance.
{% endhint %}

[Azure DevOps](https://azure.microsoft.com/en-us/products/devops) is a Microsoft-owned version control system used for managing the software development lifecycle.

Integrating Cortex with Azure DevOps allows you to:

* Automatically discover and track ownership of Azure DevOps entities
* Follow a GitOps workflow with Azure DevOps
* View information about your Azure DevOps repositories on an entity's details page, including: The repo associated with the entity, recent commits and releases in the event timeline, the most-used language in the files for that entity, the top code contributors, and their number of contributions
  * If you pull in [Azure DevOps pipeline data](#define-pipelines), you can also see pipeline runs and builds in the CI/CD section of an entity's details page.
  * If you enable the [option to pull in Azure DevOps work items](#enable-or-disable-azure-devops-work-items), you will also see a list of open work items on entity pages.
* View information about pull requests and work items in the engineering homepage
* [Create a work item from an Initiative issue](#create-a-work-item-from-an-initiative-issue) in Cortex
* Use Azure DevOps metrics in Eng Intelligence to understand key metrics and gain insight into services, incident response, and more
* Create [Scorecards](#scorecards-and-cql) that track progress and drive alignment on projects involving your repositories, Azure DevOps work items, and Azure DevOps pipeline data

## How to configure Azure DevOps with Cortex

### Configure the integration in Cortex

You can configure Azure DevOps with a Personal Access Token (PAT) or with a Service Principal with Entra ID.

{% tabs %}
{% tab title="Personal Access Token" %}
**Prerequisite**

Before you get started:

* Add a [Azure DevOps personal access token](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate) with at least the following scopes enabled:
  * Analytics: `read`
  * Build: `read`
  * Code: `read`
    * If using the [Scaffolder](/streamline/workflows/scaffolder) with Azure DevOps, you must also enable:
      * Code: `write`
      * Code: `manage`
  * Graph & Identity: `read`
  * Work Items: `read` and `write`

**Configure the Azure DevOps integration with a PAT**

1. In Cortex, navigate to the [Azure DevOps settings page](https://app.getcortexapp.com/admin/integrations/azuredevops).
   * Click **Integrations** from the main nav. Search for and select **Azure DevOps**.
2. Click **Add configuration** and select **Personal Access Token**.
3. Configure the Azure DevOps integration form:
   * **Organization**: Enter the slug for your Azure DevOps organization.
   * **Username**: Enter the username for your personal access token.
   * **Personal access token**: Enter your Azure DevOps personal access token.
   * **Host**: Optionally, if you are using a self-managed setup, enter your hostname.
4. Click **Save**.
   {% endtab %}

{% tab title="Service Principal" %}
**Prerequisite**

Before you get started:

* In your Azure portal under **Entra ID > App registrations**, [set up an app registration](https://learn.microsoft.com/en-us/entra/identity-platform/quickstart-register-app#add-credentials).
  * You will need the Client ID and Azure Tenant ID associated with this app registration.
  * When you create an app registration, a Service Principal user is also generated.
* In your Azure portal, create a Client Secret for your app registration.
  * While viewing the overview of your app registration, click the link next to "Client credentials." You will be directed to the **Certificates & secrets** page, where you can click **+New client secret** to create a secret.

**Step 1: Add your Service Principal to your Azure DevOps organization**

You must add the Service Principal user to the organization you're integrating with Cortex.

1. In Azure DevOps, from the list of organizations, select the one you will be integrating with Cortex.
2. Navigate to **Organization Settings > General > Microsoft Entra**. Connect your Entra ID directory (the one containing the app registration) with the Azure DevOps organization.
3. Navigate to **Organization Settings > General > Users,** then click **Add users**.
4. In the side panel, configure the new user:
   * **Users or Service Principals**: Enter the Service Principal associated with your app registration.
   * **Access level**: Select `Basic`.
   * **Add to projects**: Add the user to the project(s) that your Cortex integration will need access to.
   * **Azure DevOps Groups**: Select security groups. `Project Contributors` should be sufficient, or you can choose a custom security group that has Code write permissions.
     * Learn more about [permissions for Service Principals in Azure's documentation](https://learn.microsoft.com/en-us/azure/devops/integrate/get-started/authentication/service-principal-managed-identity?view=azure-devops#step-3-configure-permissions).
5. At the bottom of the side panel, click **Add**.

**Step 2: Configure the Azure DevOps integration in Cortex**

1. In Cortex, navigate to the [Azure DevOps settings page](https://app.getcortexapp.com/admin/integrations/azuredevops).
   * Click **Integrations** from the main nav. Search for and select **Azure DevOps**.
2. Click **Add configuration** and select **Service Principal**.
3. Configure the Azure DevOps integration form:
   * **Category**: Select which integration categories this configuration will apply to.
   * **Configuration alias**: Enter an alias for this configuration.
   * **Organization**: Enter the slug for your Azure DevOps organization.
   * **Client ID**: Enter the Application Client ID for your app registration.
   * **Client Secret**: Enter the Client Secret for your app registration.
   * **Azure Tenant ID**: Enter the Directory (Tenant) ID for your app registration.
   * **Host**: Optionally, if you are using a self-managed setup, enter your hostname.
4. Click **Save**.
   {% endtab %}
   {% endtabs %}

Cortex supports mapping multiple identities for a single user if you have multiple configurations of Azure DevOps. See the [Identity mapping documentation](/configure/settings/managing-users/identity-mapping) for more information.

#### **Enable or disable Azure DevOps work items**

On the [Azure DevOps settings page in Cortex](https://app.getcortexapp.com/admin/settings/azuredevops), you can choose whether Azure DevOps work items should be pulled in from Azure DevOps. Cortex recommends disabling this option if your organization does not use work items or if you are worried about running into rate limit issues.

## How to connect Cortex entities to Azure DevOps

### Import entities from Azure DevOps

See the [Create services documentation](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/add-services#creating-services) for instructions on importing entities.

### Editing the entity descriptor

In an entity's YAML, you can define a [repository](#define-a-repository), [work items](#define-work-items), [ownership](#define-ownership), and [pipelines](#define-pipelines).

#### **Define a repository**

To define an Azure DevOps repository for a given entity, add the `x-cortex-git` block to the entity's descriptor.

```yaml
x-cortex-git:
  azure:
    project: cortex
    repository: docs
    basepath: myService
    alias: accountAlias
```

| Field        | Description                                                                                                                                | Required |
| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------ | -------- |
| `project`    | The name of the project as listed under the "Projects" tab when you are logged into Azure DevOps (on the <https://dev.azure.com//> screen) | **✓**    |
| `repository` | The repo name you see when you navigate to the "Repos" section of Azure DevOps                                                             | **✓**    |
| `basepath`   | If the entity is in a monorepo (e.g. in a subdirectory), use this field to define the subdir                                               |          |
| `alias`      | Alias for the configuration in Cortex (only needed if you have opted into multi-account support)                                           |          |

Only one repository can be defined for in a given entity's YAML in the `x-cortex-git` block.

#### **Define work items**

Before adding work items to your entity YAML, make sure you have [enabled the option to pull in Azure DevOps work items](#enable-or-disable-azure-devops-work-items) in your integration settings.

To define Azure DevOps work items for a given entity, add the `x-cortex-azure-devops` block to the entity's descriptor. If there is no work item registrations, but the entity matches a repository, we will pull in all work items from the repository's project with a tag that matches the Cortex entity name, [Cortex tag](/ingesting-data-into-cortex/entities-overview/entities#cortex-tag), or the repository name.

<details>

<summary>Example WIQL</summary>

The example YAML below is based on the following example WIQL:

```
SELECT
    [System.Id],
    [System.AssignedTo],
    [System.State],
    [System.Title],
    [System.Tags]
FROM workitems
WHERE
    '[System.TeamProject] = Design Agile'
    AND '[System.WorkItemType] = User Story'
    AND '[System.State] = Active'
ORDER BY [System.ChangedDate] DESC
ASOF '02-11-2020'
```

Learn more about WIQL in [Microsoft's WIQL syntax reference](https://learn.microsoft.com/en-us/azure/devops/boards/queries/wiql-syntax?view=azure-devops).

</details>

```yaml
x-cortex-azure-devops:
    workItems:
        projects:
            - name: projectName1
              wiqls:
                - "[System.TeamProject] = 'Design Agile'"
                - "[System.WorkItemType] = 'User Story'"
                - "[System.State] = 'Active'"
                - ORDER BY [System.ChangedDate] DESC ASOF '02-11-2020'
            - name: projectName2
              alias: alias1
            - name: projectName3
              alias: alias2
```

| Field      | Description                                                                                                                         | Required |
| ---------- | ----------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `projects` | List of the projects                                                                                                                | **✓**    |
| `name`     | The project name as listed under the "Projects" tab when you are logged into Azure DevOps (on the <https://dev.azure.com//> screen) | **✓**    |
| `wiqls`    | List of WIQL conditions to filter work items fetched                                                                                |          |
| `alias`    | Alias for the configuration in Cortex (only needed if you have opted into multi-account support)                                    |          |

#### **Define ownership**

Ownership of each entity through Azure DevOps is defined through an owner of type `group`.

```yaml
x-cortex-owners:
  - type: group
    name: My Azure DevOps Team
    provider: AZURE_DEVOPS
    description: This is a description for this owner # optional
```

`name` is a case-sensitive field that corresponds to the upstream identifier of your owner from Azure DevOps.

Learn more about ownership in [Defining ownership](/ingesting-data-into-cortex/entities-overview/entities/ownership).

#### Define pipelines

You can add Azure DevOps pipelines under the `x-cortex-azure-devops` block:

```yaml
  x-cortex-azure-devops:
    pipelines:
      projects:
      - name: projectName1
        alias: config-1
        pipelines:
        - id: 1
      - name: projectName2
        alias: config-2
        pipelines:
        - id: 2
```

| Field          | Description                                                                                                                         | Required |
| -------------- | ----------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `piepelines`   | List of the pipelines                                                                                                               | **✓**    |
| `projects`     | List of the projects                                                                                                                | **✓**    |
| `name`         | The project name as listed under the "Projects" tab when you are logged into Azure DevOps (on the <https://dev.azure.com//> screen) | **✓**    |
| `alias`        | Alias for the configuration in Cortex (only needed if you have opted into multi-account support)                                    |          |
| `pipelines:id` | The Azure DevOps `system.definitionID` for the pipeline.                                                                            | **✓**    |

Learn more about Azure DevOps pipelines in [Microsoft's documentation](https://learn.microsoft.com/en-us/azure/devops/pipelines/get-started/what-is-azure-pipelines?view=azure-devops).

### Identity mappings for Azure DevOps

Cortex maps users' email addresses to discovered Azure DevOps accounts.

You can confirm users' Azure DevOps accounts are connected from [Azure DevOps identity mappings in settings](https://app.getcortexapp.com/admin/settings/azuredevops-mappings).

### Create a work item from an Initiative issue

Initiatives allow you to set deadlines for specific rules or a set of rules in a given Scorecard and send notifications to users about upcoming due dates.

From the Issues tab of an Initiative, you can automatically create a Azure DevOps work item from a failing rule:

1. Click **Create issue**.
2. In the modal that appears, fill out the form:
   * **Integration**: If you have multiple task tracking tools, select Azure DevOps from the Integration dropdown.
   * **Name**: Enter a name for the configuration.
   * **Project**: Select from the dropdown.
     * Options available in the dropdown are pulled in from the specific Azure DevOps instances configured in Settings.
3. Select the [**Work item type**](https://learn.microsoft.com/en-us/azure/devops/boards/work-items/about-work-items?view=azure-devops\&tabs=agile-process/) and the **Sub-item Type** from the respective dropdowns. Then, select how the sub-items's fields should be populated on issue creation and status change.
4. Choose to include or exclude groups of entities, or define a more advanced filter.

The issue configuration will apply to all entities that meet the filter criteria. Once an entity is passing the rule, Cortex will automatically close the associated ticket.

## Using the Azure DevOps integration

### View Azure DevOps data on entity pages in Cortex

The Azure DevOps integration will populate the **Repo** detail block on an entity's details page.

In the **Recent activity preview**, you'll find the recent commits and releases. These will also appear in the event timeline.

These data will appear for entities imported from a Git source or those that have a Git repo defined in their YAMLs.

#### **Events**

On an entity's **Events** page, you can find all of the commits and releases associated with that entity. Each is hyperlinked to the commit or release page in Azure DevOps and includes a timestamp.

#### **CI/CD**

From the **CI/CD > Deploys** page in the entity's sidebar, see a history of pipeline runs.

#### **Repository**

You can access more detailed information pulled from Azure DevOps under **Repository** in the sidebar. At the top of the repository page, you'll find the repo associated with that entity and the most-used language in files for that entity. In the **Top contributors** block, you'll find the three users who have contributed the most code and the number of their contributions.

In the **Commits** section, you'll find the 10 most recent commits and metadata about each. Below **Commits** is the **Recent releases** section, which includes the 5 most recent releases.

#### **Issue tracking**

In the **Issue tracking** section, you can find a list of open [Azure DevOps work items](https://learn.microsoft.com/en-us/azure/devops/boards/work-items/about-work-items?view=azure-devops\&tabs=agile-process). Each work item will show the title, summary, assignees, priority, and date created.

#### **Packages**

Packages are automatically scraped from your Git repos or they can be submitted via the [packages API](/api/readme/packages). The package file must be in the root of your repository — or, if you're using `basepath`, in the root of the subdirectory — to be scraped by Cortex. You can query an entity's packages in [CQL explorer](https://app.getcortexapp.com/admin/cql-explorer) using `packages()`.

To view packages, click **Packages** in the entity's sidebar.

The following package types are automatically scraped from repositories:

* JavaScript / Node.js: `package.json`, `package-lock.json`, `yarn.lock`, `pnpm-lock.yaml`
* Python: `requirements.txt`, `pipfile.lock`
* .NET (C#): `packages.lock.json`
* Java: `pom.xml`
* Go: `go.sum`

All other files of these types can be added via the [packages API](/api/readme/packages).

### Engineering homepage

The Azure DevOps integration enables Cortex to pull information about pull requests and work items into the [homepage](/streamline/homepage). You can find your open pull requests, any pull requests assigned to you for review, and any work items assigned to you.

Pull requests and work items from Azure DevOps are refreshed every 5 minutes.

### Eng Intelligence

The [Eng Intelligence tool](https://app.getcortexapp.com/admin/eng-intelligence) also uses pull request data from Azure DevOps to generate metrics:

* Average PR open to close time
* Avg time to first review
* Avg time to approval
* PRs opened
* Weekly PRs merged
* Avg PRs reviewed/week
* Avg commits per PR

Read more about how Eng Intelligence tracks metrics for teams and users in the [Eng Intelligence documentation](/improve/eng-intelligence).

### Scorecards and CQL

With the Azure DevOps integration, you can create Scorecard rules and write CQL queries based on Azure DevOps work items.

See more examples in the [CQL Explorer](https://app.getcortexapp.com/admin/cql-explorer) in Cortex.

<details>

<summary>Approvals required to merge</summary>

Total number of approval required to merge a pull request into a repository. Defaults to 0 if no approvals are defined.

**Definition:** `git.numOfRequiredApprovals()`

**Examples**

For a security or development maturity Scorecard, you can write a rule to make sure at least one approval is required for a pull request:

```
git.numOfRequiredApprovals() >= 1
```

By having a rigorous PR process in place for a repo, you can make sure changes aren't made that create vulnerabilities. This kind of rule could also be used in a best practices or project standards Scorecard.

You can also use a similar expression in the Query Builder to find entities lacking approval:

```
git.numOfRequiredApprovals() < 1
```

</details>

<details>

<summary>Branches</summary>

List all live branches with some basic metadata:

* Head
* Is protected
* Name

**Definition:** `git.branches(): List<GitBranch>`

**Example**

For a development best practices Scorecard, you can make sure that branches associated with an entity match a standard naming convention:

```
git.branches().all((branch) => branch.name.matches("(main|master|feat-.*|bug-.*|task-.*
```

</details>

<details>

<summary>Branch protection details</summary>

Find details for a specified branch or default branch if none is specified.

**Definition:** `git.branchProtection(branchName: Text?): GitBranchProtection`

**Examples**

For a security Scorecard, you can write a rule to make sure the default branch is protected:

```
git.branchProtection() != null
```

Or to make sure the main branch is protected:

```
git.branchProtection("main") != null
```

Because vulnerabilities in the default branch are critical, this rule should be in one of the first couple levels. A higher-level rule might make sure that branch protection checks are set:

```
git.branchProtection("main").requiredStatusChecks.length > 0
```

You can also use the Query Builder to find entities with unprotected default branches:

```
git.branchProtection() = null
```

</details>

<details>

<summary>Commits</summary>

Get the latest commits (to a maximum of 100) for a defined lookback period (defaulting to 7 days).

These results can be filtered based on branch name, using the default branch if no other branch is provided.

**Definition:** `git.commits()`

**Examples**

You can use the `git.commits()` expression in a security Scorecard to make sure entities have fewer than three commits to a "security-fixes" branch in the last week:

```
git.commits(branch="security-fixes").length < 3
```

Entities passing this rule will include those that haven't needed three or more security fixes. This can indicate that there aren't vulnerabilities in a given entity's code, but could also suggest that fixes aren't being implemented.

Using this rule in conjunction with one focused on vulnerabilities could provide the extra context needed to gain a better understanding of what's happening.

</details>

<details>

<summary>Default branch</summary>

Default branch for the entity's repository or `main` when null.

**Definition:** `git.defaultBranch()`

**Examples**

If default branches should always be named "main," you can write a rule in a best practices Scorecard to make sure entities are compliant:

```
git.defaultBranch().matches("main")
```

</details>

<details>

<summary>File contents</summary>

Load the contents of a file from the entity's associated repository.

The contents can be validated by using string comparison operations or parsed by the built-in `jq` function. The `jq` function will automatically coerce file contents of JSON or YAML formats.

**Definition:** `git.fileContents(<filename: Text>)`

**Examples**

For a Scorecard focused on development maturity, you could use the `git.fileContents()` rule to enforce that a CI pipeline exists, and that there is a testing step defined in the pipeline:

```
git.fileContents(“circleci/config.yml”).matches(“.*npm test.*”) - Enforce that a CI pipeline exists, and there is a testing step defined in the pipeline
```

A best practices Scorecard, meanwhile, could use this expression for a number of rules:

* To make sure node engine version in specified in the `package.json` file:

  ```
  jq(git.fileContents("package.json"), ".engines.node") != null
  ```
* To make sure TypeScript projects have a `tsconfig.json` file checked in:

  ```
  jq(git.fileContents("package.json"), ".devDependencies | with_entries(select(.key == \"typescript\")) | length") == 0 or git.fileExists("tsconfig.json")
  ```
* To make sure projects using yarn do not allow NPM:

  ```
  jq(git.fileContents("package.json"), ".engines.yarn") == null or jq(git.fileContents("package.json"), ".engine.npm") = "please-use-yarn"
  ```
* And to ensure the yarn version being used is not deprecated:

  ```
  jq(git.fileContents("package.json"), ".engines.yarn") == null or !(semver("1.2.0") ~= semverRange(jq(git.fileContents("package.json"), ".engines.yarn")))
  ```

</details>

<details>

<summary>File exists</summary>

Check if file exists from within the entity's associated repository.

**Definition:** `git.fileExists(<filename: Text>)`

**Examples**

For a development best practices Scorecard, this expression can be used for a rule that makes sure developers are checking in lockfiles to ensure repeatable builds:

```
git.fileExists(“package-lock.json”)
```

In the Query builder, you can use this expression with a wildcard to find entities with unit tests enabled:

```
git.fileExists(*Test.java”)
```

Or to find entities with an outdated Terraform version:

```
git.fileExists("terraform/versions.tf") and !git.fileContents("terraform/versions.tf").matchesIn("required_version =! \"[~>= ]{0,3}0\\.(12|13)")
```

</details>

<details>

<summary>Has Cortex YAML (GitOps)</summary>

When enabling GitOps to manage entity descriptors, Cortex checks for a checked in file `./cortex.yaml` at the root directory. This rule can help track migrations from UI editing to GitOps for entity descriptor management.

**Definition:** `git.hasCortexYaml()`

**Examples**

If you're using a Scorecard to track a migration from Cortex UI to GitOps, you can use this rule to make sure entities are set up for GitOps management of entity descriptors:

```
git.hasCortexYaml() == true
```

</details>

<details>

<summary>Git repository set</summary>

Check if entity has a registered Git repository.

**Definition:** `git (==/!=) null`

**Examples**

A Scorecard focused on best practices or standards will likely include a rule in its first level making sure a Git repository is set up:

```
git != null
```

If an entity is failing this rule, it can indicate broader issues with the integration or explain why an entity isn't functioning as expected.

</details>

<details>

<summary>Last commit details</summary>

Provides last commit details.

**Definition:** `git.lastCommit()`

**Examples**

Depending on best practices at your organization, you may want to confirm the last commit for a given entity is no older than 3 days:

```
datetime(git.lastCommit().date).fromNow() > duration("P-3D")
```

Confirming whether a service was updated recently can help team members catch outdated code sooner. Plus, if there is a security issue, you can quickly determine which services have or have not been updated to patch the vulnerability.

For a best practices Scorecard, you can also use this expression to make sure the entity's last commit message follows conventional commit guidelines:

```
git.lastCommit().message.matches("^(feat|fix|docs|style|refactor|test|chore)(\\(.+\\))?:*")
```

</details>

<details>

<summary>List pipelines</summary>

List pipelines with metadata, including name, id, url, and project name.

**Definition**: `azureDevops.pipelines()`

**Examples**

You could write a Scorecard rule to ensure that the entity has at least 1 pipeline that scans vulnerabilities:

```
azureDevops.pipelines().any(pipeline => pipeline.name.matchesIn("Vuln scan"))
```

You could write a Scorecard rule to ensure that the entity has an Azure DevOps pipeline set:

```
azureDevops.pipelines() != null
```

</details>

<details>

<summary>Pipeline build success rate</summary>

Percentage of build pipelines that complete successfully.

This is calculated against builds on the default branch for commits in the last 30 days: `# successful builds / (# successful + # failed)`.

**Definition:** `git.percentBuildSuccess()`

**Examples**

This expression can be used in a development maturity Scorecard to write a rule making sure at least 95% of build runs are successful:

```
git.percentBuildSuccess() >= 0.95
```

</details>

<details>

<summary>Pipeline metrics</summary>

List pipelines with metrics. Metrics contains the successRate & averageDuration of a pipeline.

**Definition**: `azureDevops.pipelineMetrics()`

**Examples**

You could write a Scorecard rule to ensure pipelines have a successRate higher than 95%:

```
azureDevops.pipelineMetrics().all((pipeline) => pipeline.metrics.successRate > 0.95)
```

</details>

<details>

<summary>Pipeline runs</summary>

Get pipelines runs meeting the given filter criteria, which includes results, states. Results include "succeeded", "failed", "canceled", "unknown", states include "completed", "inProgress", "canceling", "unknown".

**Definition**: `azureDevops.pipelineRuns()`

**Examples**

List pipeline runs that are opened and reviewed within 1 day:

```
azureDevops.pipelineRuns().filter(run => run.run.completedDate != null).map((run) => run.run.createdDate.until(run.run.completedDate)).averageDuration() < duration("P1D")
```

</details>

<details>

<summary>Pull requests</summary>

Lists pull requests opened during a defined lookback period.

* Approval date
* Author
* Date closed
* Date opened
* First review date
* Is draft
* Last updated
* Number of commits
* Number of lines added
* Number of lines deleted
* Organization
* Repository
* Source
* Status
* URL

**Definition:** `git.pullRequests()`

**Example**

You can use the `git.pullRequests()` query to find entities that have a small number of pull requests opened in the last two weeks:

```
git.pullRequests(lookback=duration("P14D")).length < 3
```

This can highlight entities that haven't been updated recently, which may be especially useful when entities have to be updated to address a vulnerability.

**Example**

You can count only non-draft pull requests:

```
git.pullRequests(lookback=duration("P14D")).filter(pr => !pr.isDraft).length < 3
```

</details>

<details>

<summary>Recency of last commit</summary>

Calculates the duration of time between Scorecard evaluation and the date of the last commit from the entity's Git repository.

**Definition:** `git.lastCommit().freshness`

**Examples**

One of the first rules you might write for a Scorecard focused on development maturity or security is one validating that the last commit was within the last month:

```
git.lastCommit().freshness < duration("P1M")
```

As counterintuitive as it may seem, services that are committed too infrequently are actually at more risk. People who are familiar with the service may leave a team, institutional knowledge accumulates, and from a technical standpoint, the service may be running outdated versions of your platform tooling.

</details>

<details>

<summary>Reviews</summary>

List reviews left during a defined lookback period.

* Organization
* Repository
* Review date
* Reviewer

**Definition:** `git.reviews()`

**Examples**

A development maturity Scorecard might use the `git.reviews()` expression to make sure that there is a rigorous review process in place before changes are implemented:

```
git.reviews(lookback=duration("P7D")).length > 25
```

This rule makes sure that there are more than 25 reviews left in the last week.

</details>

<details>

<summary>Search repository files</summary>

Find all instances of code search query from within a repository.

Can filter by path, file name (extension required in file name), or extension. Filters can use \* for glob matching. Supplying a query is required.

**Definition:** `git.codeSearch((query = <query: Text>) (, path = <path: Text>) (, fileName = <fileName: Text>) (, fileExtension = <fileExtension: Text>)): List<GitSearchResult>`

**Examples**

You can use the `git.codeSearch()` expression to query for entities that have certain components, like icons:

```
git.codeSearch(query = "icon", fileExtension = "css").length > 0
```

</details>

<details>

<summary>Top repository language</summary>

Find top used language for a repository, if available.

**Definition:** `git.topLanguage()`

**Examples**

Let's say the primary language developers should be using is Kotlin. You can write a rule to make sure that the top language associated with entities is Kotlin:

```
git.topLanguage() == "kotlin"
```

You can also use this expression to query for entities that don't have Kotlin as the top language to identify those that need to be updated:

```
git.topLanguage() != "kotlin"
```

</details>

<details>

<summary>Work items</summary>

Number of **unresolved** work items associated with the entity, where unresolved is defined as the WIQL \[System.State] NOT IN ('Closed', 'Done', 'Completed', 'Inactive', 'Removed').

**Definition:** `azureDevops.workItems()`

**Examples**

For a Scorecard measuring entity maturity, you can use this expression to make sure entities have fewer than 10 Azure DevOps work items:

```
azureDevops.workItems().length <= 10
```

</details>

<details>

<summary>Work items from WIQL query</summary>

Number of work items associated with the entity based on arbitrary WIQL query.

**Definition:** `azureDevops.workItems(query: Text | Null)`

**Examples**

For a more specific rule in an entity maturity Scorecard, you can use this expression with a WIQL query to make sure entities have no more than 3 tickets with "Doing" status and highest priority.

```
jira.workItems("System.State = \"Doing\" AND Microsoft.VSTS.Common.Priority = 1").length <= 3
```

</details>

### View integration logs <a href="#still-need-help" id="still-need-help"></a>

{% hint style="info" %}
This feature is available in Cortex cloud.
{% endhint %}

While viewing an integration's settings page, select the **Logs** tab to view error logs from the last 7 days. You can filter the logs list by configuration and by operation (for example, you could filter to view errors surfaced only via Scorecards).

<div align="left" data-with-frame="true"><figure><img src="/files/x8JmoPqXZTJ7YHeFJpOA" alt="The &#x27;Logs&#x27; tab on an integration&#x27;s settings page shows error information over the past 7 days."><figcaption></figcaption></figure></div>

Click into a row to get more information, including time stamp, status code, full error, and request path.

## Background sync

Cortex conducts a background sync of Azure DevOps identities every day at 10 a.m. UTC. Pull requests and work items are refreshed every 5 minutes.

## Still need help?[​](https://docs.cortex.io/docs/reference/integrations/aws#still-need-help) <a href="#still-need-help" id="still-need-help"></a>

The following options are available to get assistance from the Cortex Customer Engineering team:

* **Email**: <help@cortex.io>, or open a support ticket in the in app Resource Center
* **Slack**: Users with a connected Slack channel will have a workflow added to their account. From here, you can either @CortexTechnicalSupport or add a `:ticket:` reaction to a question in Slack, and the team will respond directly.

Don’t have a Slack channel? Talk with your Customer Success Manager.


# Azure Resources

{% hint style="info" %}
Cortex connects to many third-party vendors whose system interfaces frequently change. As a result, integration behavior or configuration steps may shift without notice. If you encounter unexpected issues, check with your system administrator or refer to the vendor's documentation for the most current information. Additionally, integration sync times vary and are subject to scheduling overrides and timing variance.
{% endhint %}

[Azure Resources](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/overview) provides on-demand cloud computing platforms and APIs. Cortex uses the Azure Resource API to pull in resource details and import entities such as SQL servers, virtual machines, virtual networks, load balancers, and others.

Integrating Azure Resources with Cortex allows you to:

* [Automatically import entities](#enable-automatic-discovery-of-azure-resource-entities) and track ownership of entities
* Create [Scorecards](#scorecards-and-cql) to drive alignment and track progress on projects involving resources from Azure

{% hint style="info" %}
Cortex conducts a background sync of Azure Resources every day at 00:00 a.m. UTC and an ownership sync every day at 6 a.m. UTC.
{% endhint %}

## How to configure Azure Resources with Cortex

### Prerequisites

Before getting started, you will need the following information. These can be found in the **Enterprise applications** section of Azure:

* Azure tenant ID
* Azure client ID and [client secret](https://learn.microsoft.com/en-us/entra/identity-platform/quickstart-register-app#add-credentials)
* Azure subscription ID
  * Ensure that the service principal for the subscription ID has a [Reader role](https://learn.microsoft.com/en-us/entra/identity-platform/howto-create-service-principal-portal#assign-a-role-to-the-application).

### Configure the integration in Cortex

1. In Cortex, navigate to the [Azure Resources settings page](https://app.getcortexapp.com/admin/integrations/azureresources).
   * Click **Integrations** from the main nav. Search for and select **Azure Resources**.
2. Click **Add configuration**.
3. Configure the Azure Resources integration form:
   * **Account alias**: Enter your Azure account alias. Account aliases are used to tie service registrations to different configuration accounts.
   * **Azure tenant ID**: Enter your Azure tenant ID.
   * **Client ID** and **Client secret**: Enter your Azure client ID and secret.
   * **Subscription ID**: Enter your Azure subscription ID.
4. Click **Save**.
   * You will be redirected to the Azure Resources Settings page in Cortex, where you can optionally choose to include only specified Azure resource types for this integration. You can also enable [automatic import](#enable-automatic-discovery-of-azure-resource-entities) for any discovered entities of known types.

After saving your configuration, you are redirected to the integration settings page in Cortex. In the upper right corner of the page, click **Test configuration** to ensure Azure Resources was configured properly.

## How to connect Cortex Entities to Azure Resources

{% hint style="info" %}
For Azure Resources, Cortex replaces non-alphanumeric characters in entity names with a space. For example, `resource_1` would become `resource 1`.

For the [Cortex tag](/ingesting-data-into-cortex/entities-overview/entities#cortex-tag), Cortex replaces non-alphanumeric characters with `-` and lowercases the letters. If multiple special characters appear together in a tag, Cortex replaces the group of characters with only one `-`. For example, `mY_e%ntity#$_tag` would become `my-e-ntity-tag`.
{% endhint %}

### Enable automatic discovery of Azure Resource entities

You can configure automatic import from Azure:

1. In Cortex, navigate to the [Entities Settings page](https://app.getcortexapp.com/admin/settings/entities).
2. Next to **Auto import from AWS, Azure, and/or Google Cloud**, click the toggle to enable the import.\\

   <figure><img src="/files/p4fNmdV0qFSbUMX1YwGD" alt=""><figcaption></figcaption></figure>

### Discover ownership for Azure Resources

Cortex can automatically discover ownership for your Azure resources. To configure this:

* Make sure that your Azure resources have a tag matching the `x-cortex-tag` of the corresponding Cortex team
* Enable the “Sync ownership from Azure” toggle in the [Azure Resources Settings page](https://app.getcortexapp.com/admin/settings/azureresources) in Cortex.
  * By default, Cortex looks for the `owner` tag. You can also customize the tag key name on the Settings page.

Cortex syncs ownership from Azure Resources every day at 6 a.m. UTC.

### Define a dependency

Cortex automatically discovers dependencies between your services and resources by scanning for resources with specific Azure Resources tags. By default, a service will have dependencies on any Cortex resource that has a corresponding Azure Resources resource with Azure Resources tag key = "service" and tag value = the service's Cortex tag.

On the [Azure Resources settings page](https://app.getcortexapp.com/admin/settings/azureresources), you can customize the tag key names for dependencies.

For more information on defining dependencies, please see the [Dependencies documentation](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/dependencies).

### Import entities from Azure Resources

See the [Create services documentation](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/add-services#creating-services) for instructions on importing entities.

### Editing the entity descriptor

You can associate a Cortex entity with one or more Azure Resources entities. Cortex will display those Azure Resources entities' metadata on the Cortex entity page.

When the entity is connected to Azure, the entity YAML will look like the following:

```yaml
x-cortex-azure:
  ids:
  - id: /subscriptions/1fbb2da1-2ce7-45e4-b85f-676ab8e685b9/resourceGroups/GROUP1/providers/Microsoft.Compute/disks/vm1_disk1_3d9f85717666435e9e87e4883d31a7e9
    alias: my-default-alias # alias is optional and only relevant if you have opted into multi account support
  - id: /subscriptions/1fbb2da1-2ce8-45e4-b85f-676ab8e685b0/resourceGroups/GROUP2/providers/Microsoft.Compute/disks/vm1_disk1_3d9f85717666435e9e87e4883d31a7e0
    alias: my-other-alias # alias is optional and only relevant if you have opted into multi account support
```

## Using the Azure Resources integrations

### Scorecards and CQL

With the Azure Resources integration, you can create Scorecard rules and write CQL queries based on Azure Resources details.

See more examples in the [CQL Explorer](https://app.getcortexapp.com/admin/cql-explorer) in Cortex.

<details>

<summary>Get Azure Resource details for entity</summary>

Get Azure Resource details for an entity.

**Definition:** `azureResource.details(): Object`

**Examples**

In a Scorecard, you can write a rule to make sure an entity has Azure Resource details:

```
azureResource.details() != null
```

Make sure an entity has an environment tag:

```
azureResource.details().resources.filter((resource) => jq(resource, ".metadata.\"environment\"") != null).length > 0
```

Make sure an entity has a health check:

```
jq(azureResource.details(), ".resources[].metadata.siteConfig.healthCheckPath") != null
```

Make sure an entity has a tag with a certain key and value:

```
azureResource.details().resources.filter((resource) => resource.tags.get("tag-key") == "tag-value").length > 0
```

</details>

<details>

<summary>Availability zones</summary>

Availability zone data (VM Scale Sets, Redis, Application Gateways) is a first-class `.zones` field, sourced directly from Azure Resource Graph.

If you have existing "Resource Redundancy" rules for these resource types, update them to reference `.zones` instead of deriving zone data from the ARM export template.

**Example**

```
azureResource.details().resources.filter((resource) => resource.zones != null && resource.zones.length > 0).length > 0
```

</details>

<details>

<summary>App Service health-check path and minimum TLS version</summary>

Cortex reads App Service configuration data, including `healthCheckPath` and minimum TLS version.

Existing "Health Check" and App Service Scorecard rules will continue to work as-is, no Scorecard rule changes needed.

**Example**

```
azureResource.details().resources.filter((resource) => resource.zones != null && resource.zones.length > 0).length > 0
```

</details>

### View integration logs <a href="#still-need-help" id="still-need-help"></a>

{% hint style="info" %}
This feature is available in Cortex cloud.
{% endhint %}

While viewing an integration's settings page, select the **Logs** tab to view error logs from the last 7 days. You can filter the logs list by configuration and by operation (for example, you could filter to view errors surfaced only via Scorecards).

<div align="left" data-with-frame="true"><figure><img src="/files/x8JmoPqXZTJ7YHeFJpOA" alt="The &#x27;Logs&#x27; tab on an integration&#x27;s settings page shows error information over the past 7 days."><figcaption></figcaption></figure></div>

Click into a row to get more information, including time stamp, status code, full error, and request path.

## Troubleshooting and FAQ

**Why is the Azure resource type `microsoft-resources-subscriptions-resourcegroups` not pulling in Azure Resource details?**

Cortex pulls from the Azure Resource API, but not from the Azure Resource Group API. If you would like to submit a feature request for support of Azure Resource Groups, please contact our customer engineering team.

**Why is ARM template data sometimes missing or stale?**

Cortex uses the Azure ARM export template endpoint to ingest resource data for some resource types. This endpoint has known reliability limitations [acknowledged in Microsoft's documentation](https://learn.microsoft.com/en-us/azure/azure-resource-manager/templates/export-template-portal#limitations), which can cause intermittent failures that result in missing or outdated data.

Cortex is actively migrating away from ARM template-based ingestion toward Azure Resource Graph and the resource metadata endpoint. In the interim, if you see empty or stale data for a resource, this is likely caused by an ARM export failure on the Microsoft side.


# BambooHR

{% hint style="info" %}
Cortex connects to many third-party vendors whose system interfaces frequently change. As a result, integration behavior or configuration steps may shift without notice. If you encounter unexpected issues, check with your system administrator or refer to the vendor's documentation for the most current information. Additionally, integration sync times vary and are subject to scheduling overrides and timing variance.
{% endhint %}

## Overview

[BambooHR](https://www.bamboohr.com/) is a Human Resources Information System (HRIS) solution that allows you to define organizational membership. Integrate Cortex with BambooHR to automatically sync team memberships, giving you insight into entity ownership.

## How to configure BambooHR with Cortex

### Prerequisite

Before getting started, create a [BambooHR API key](https://documentation.bamboohr.com/docs#section-authentication).

### Configure the integration in Cortex

1. In Cortex, navigate to the [BambooHR settings page](https://app.getcortexapp.com/admin/integrations/bamboohr).
   * Click **Integrations** from the main nav. Search for and select **BambooHR**.
2. Click **Add configuration**.
3. Configure the BambooHR integration form:
   * **Subdomain**: Enter your BambooHR subdomain.
     * This can be found in your app URL, e.g., `subdomain.bamboohr.com`.
   * **API token**: Enter your BambooHR API token.
   * **Report ID**: Optionally, enter a Report ID to filter the list of employees.
     * We recommend entering a Report ID if you have a custom BambooHR Report that has the authoritative list of active employees.
     * This value can be found in the app URL, e.g., `subdomain.bamboohr.comreports/custom/New+Hires/REPORTID`
   * **Employee ownership field**: Optionally, enter the ownership field name.
     * If left blank, Cortex defaults to finding the list of employees using their `division` followed by their `department`.
4. Click **Save**.

## How to connect Cortex entities to BambooHR

### Import entities from BambooHR

See the [Create teams documentation](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/teams#creating-a-team) for instructions on importing entities.

### Editing the entity descriptor

Ownership of each catalog entity through BambooHR is defined through an owner of type `group`.

```yaml
x-cortex-owners:
  - type: group
    name: My Bamboo HR Team
    provider: BAMBOO_HR
    description: This is a description for this owner # optional
```

The `name` should be exactly equal to the [value in the Team field](#team-field).

## Using the BambooHR integration

### Scorecards and CQL

With the BambooHR integration, you can create Scorecard rules and write CQL queries based on BambooHR teams.

See more examples in the [CQL Explorer](https://app.getcortexapp.com/admin/cql-explorer) in Cortex.

<details>

<summary>All ownership details</summary>

A special built-in type that supports a null check or a count check, used to enforce ownership of entities.

**Definition:** `ownership: Ownership | Null`

**Example**

An initial level in a security Scorecard might include a rule to ensure an entity has at least one team as an owner:

```
ownership.teams().length > 0
```

</details>

<details>

<summary>All owner details</summary>

List of owners, including team members and individual users, for each entity

**Definition:** `ownership.allOwners()`

**Example**

The Scorecard might include a rule to ensure that entity owners all have an email set:

```
ownership.allOwners().all((member) => member.email != null)
```

</details>

<details>

<summary>Team details</summary>

List of teams for each entity

**Definition:** `ownership.teams(): List<Team>`

**Example**

The Scorecard might include a rule to ensure that an entity owners all have a description and are not archived:

```
ownership.teams().all(team => team.description != null and team.isArchived == false)
```

</details>

### View integration logs <a href="#still-need-help" id="still-need-help"></a>

{% hint style="info" %}
This feature is available in Cortex cloud.
{% endhint %}

While viewing an integration's settings page, select the **Logs** tab to view error logs from the last 7 days. You can filter the logs list by configuration and by operation (for example, you could filter to view errors surfaced only via Scorecards).

<div align="left" data-with-frame="true"><figure><img src="/files/x8JmoPqXZTJ7YHeFJpOA" alt="The &#x27;Logs&#x27; tab on an integration&#x27;s settings page shows error information over the past 7 days."><figcaption></figcaption></figure></div>

Click into a row to get more information, including time stamp, status code, full error, and request path.

## Background sync

Cortex conducts an ownership sync for BambooHR teams every day at 6 a.m. UTC.

## Still need help?[​](https://docs.cortex.io/docs/reference/integrations/aws#still-need-help) <a href="#still-need-help" id="still-need-help"></a>

The following options are available to get assistance from the Cortex Customer Engineering team:

* **Email**: <help@cortex.io>, or open a support ticket in the in app Resource Center
* **Slack**: Users with a connected Slack channel will have a workflow added to their account. From here, you can either @CortexTechnicalSupport or add a `:ticket:` reaction to a question in Slack, and the team will respond directly.

Don’t have a Slack channel? Talk with your Customer Success Manager.


# Bitbucket

{% hint style="info" %}
Cortex connects to many third-party vendors whose system interfaces frequently change. As a result, integration behavior or configuration steps may shift without notice. If you encounter unexpected issues, check with your system administrator or refer to the vendor's documentation for the most current information. Additionally, integration sync times vary and are subject to scheduling overrides and timing variance.
{% endhint %}

[Bitbucket](https://bitbucket.org/product/) is a Git-based version control system from Atlassian. You can use Bitbucket to drive insights into repository details in the Catalog and Scorecard rules.

Integrating Bitbucket with Cortex allows you to:

* Discover and track ownership of Bitbucket entities
* [View Bitbucket data on entity pages](#view-bitbucket-information-on-entity-pages-in-cortex) in Cortex
* Follow a [GitOps](/configure/gitops) workflow with Bitbucket
* View information about pull requests in the [engineering homepage](#engineering-homepage)
* Use Bitbucket metrics in [Eng Intelligence](#eng-intelligence) to understand key metrics and gain insight into services, incident response, and more
* Create [Scorecards](#scorecards-and-cql) that track progress and drive alignment on projects involving your Bitbucket repositories

{% hint style="info" %}
Bitbucket data in [Eng Intelligence](#eng-intelligence) and in the [engineering homepage](#dev-homepage) is available in private beta. Please contact your Cortex Customer Success Manager for access.
{% endhint %}

## How to configure Bitbucket with Cortex

There are multiple options for integrating with Bitbucket:

* Cloud: Using a workspace token (recommended), the Cortex Atlassian app, or an app password.
* On-prem: Using Basic auth or using OAuth
* You can also integrate using Cortex Axon Relay, a relay broker that allows you to securely connect your on-premises Bitbucket data.

See the tabs below for instructions on the method you choose.

{% tabs %}
{% tab title="Workspace token" %}
**Configure Cortex with Bitbucket using a workspace token**

**Step 1: Generate a workspace token in Bitbucket**

1. In Bitbucket, navigate to **Settings > Workspace settings > Access tokens**.
2. Create a workspace-level access token. Include the following scopes:
   1. `Repositories: Read`
   2. `Pull requests: Read`

**Step 2: Configure the integration in Cortex**

1. In Cortex, navigate to the [Bitbucket settings page](https://app.getcortexapp.com/admin/integrations/bitbucket).
   * Click **Integrations** from the main nav. Search for and select **Bitbucket**.
2. For the configuration type, select **Cloud (workspace token)**.\
   ![](/files/fBpwWgXGCYJY5y4CLTxA)
3. Configure the form:
   * **Account alias**: Enter an alias for the account. Aliases are used to tie service registrations to different configuration accounts.
   * **Token**: Enter the workspace token you generated in Bitbucket.
4. Click **Save**.

**Step 3: Set your Bitbucket workspace**

1. On the [Bitbucket Settings page](https://app.getcortexapp.com/admin/settings/bitbucket) in Cortex, next to your integration's alias, click **Add workspace**.\
   ![Click on Add workspace](/files/hxFsB4EpyluMoTf0yU0h)
2. In the "Workspace configuration" modal, enter your Workspace name.
   * You can find this in Bitbucket under **Settings > Workspace settings**.
3. Click **Save**.
   {% endtab %}

{% tab title="Atlassian app" %}
**Configure Cortex with Bitbucket using the Atlassian app**

**Step 1: Install the Cortex Atlassian app**

Follow the [installation instructions in the Atlassian Marketplace](https://marketplace.atlassian.com/apps/1225295/cortex?tab=installation\&hosting=cloud) for the Cortex app.

**Step 2: Configure the integration in Cortex**

1. In Cortex, navigate to the [Bitbucket settings page](https://app.getcortexapp.com/admin/integrations/bitbucket).
   * Click **Integrations** from the main nav. Search for and select **Bitbucket**.
2. Click **Add Bitbucket configuration**.
3. For the configuration type, select select **Atlassian app**.

   <div align="left"><figure><img src="/files/fBpwWgXGCYJY5y4CLTxA" alt="" width="270"><figcaption></figcaption></figure></div>
4. Configure the "Add Bitbucket configuration" form:
   * **Account alias**: Enter an alias for the account. Aliases are used to tie service registrations to different configuration accounts.
5. Click **Save**.
   * You will be redirected to the Bitbucket Settings page in Cortex.

**Step 3: Connect to Atlassian from Cortex**

1. On the [Bitbucket settings page](https://app.getcortexapp.com/admin/settings/bitbucket) in Cortex, click **Atlassian Application**. ![Click on Atlassian Application](/files/ywxTAZI7C5HRvUTp4ncd)
2. In the popup that appears, click **Grant access** to authorize Cortex access to your Atlassian Workspace.
   {% endtab %}

{% tab title="App password" %}
**Configure Cortex with Bitbucket using an app password**

{% hint style="warning" %}
Bitbucket is [deprecating app passwords on June 9, 2026](https://www.atlassian.com/blog/bitbucket/bitbucket-cloud-transitions-to-api-tokens-enhancing-security-with-app-password-deprecation). If you are currently using an app password, we recommend switching to a workspace token or the Atlassian app before that date.
{% endhint %}

**Step 1: Create an app password**

* Follow Atlassian's documentation to [create an app password for Bitbucket](https://support.atlassian.com/bitbucket-cloud/docs/create-an-app-password/).
  * Make sure to give the app password the following minimum permissions: `Repositories: Admin`, `Repositories: Read`, `Pull requests: Read`

**Step 2: Configure the integration in Cortex**

1. In Cortex, navigate to the [Bitbucket settings page](https://app.getcortexapp.com/admin/integrations/bitbucket).
   * Click **Integrations** from the main nav. Search for and select **Bitbucket**.
2. Click **Add configuration**.
3. For the configuration type, select **Cloud (basic auth)**.

   <div align="left"><figure><img src="/files/fBpwWgXGCYJY5y4CLTxA" alt="" width="270"><figcaption></figcaption></figure></div>
4. Configure the "Add Bitbucket configuration" form:
   * **Account alias**: Enter an alias for the account. Aliases are used to tie service registrations to different configuration accounts.
   * **Username**: Enter your Bitbucket username.
     * You can find this in Bitbucket under **Personal settings > Account settings > Bitbucket profile settings**.
   * **Password**: Enter the app password you created in the previous steps.
5. Click **Save**.
   * You will be redirected to the Bitbucket Settings page.

**Step 3: Set your Bitbucket workspace**

1. On the [Bitbucket Settings page](https://app.getcortexapp.com/admin/settings/bitbucket) in Cortex, next to your integration's alias, click **Add workspace**.\
   ![Click on Add workspace](/files/hxFsB4EpyluMoTf0yU0h)
2. In the "Workspace configuration" modal, enter your Workspace name.
   * You can find this in Bitbucket under **Settings > Workspace settings**.
3. Click **Save**.
   {% endtab %}

{% tab title="Basic" %}
**Configure Cortex with Bitbucket using a on-premises basic auth**

{% hint style="warning" %}
Bitbucket is [deprecating app passwords on June 9, 2026](https://www.atlassian.com/blog/bitbucket/bitbucket-cloud-transitions-to-api-tokens-enhancing-security-with-app-password-deprecation). If you are currently using an app password for basic auth, we recommend switching to an alternative authentication method before that date.
{% endhint %}

**Step 1: Create an app password**

* Follow Atlassian's documentation to [create an app password for Bitbucket](https://support.atlassian.com/bitbucket-cloud/docs/create-an-app-password/).
  * Make sure to give the app password the following minimum permissions: `Repositories: Admin`, `Repositories: Read`, `Pull requests: Read`

**Step 2: Configure the integration in Cortex**

1. In Cortex, navigate to the [Bitbucket settings page](https://app.getcortexapp.com/admin/integrations/bitbucket).
   * Click **Integrations** from the main nav. Search for and select **Bitbucket**.
2. Click **Add configuration**.
3. For the configuration type, select **On-prem (basic auth)**.

   <div align="left"><figure><img src="/files/fBpwWgXGCYJY5y4CLTxA" alt="" width="270"><figcaption></figcaption></figure></div>
4. Configure the "Add Bitbucket configuration" form:
   * **Account alias**: Enter an alias for the account. Aliases are used to tie service registrations to different configuration accounts.
   * **Host**: Enter your Bitbucket on-prem host, e.g., `https://bitbucket.example.com`.
   * **Username**: Enter your Bitbucket username.
     * You can find this in Bitbucket under **Personal settings > Account settings > Bitbucket profile settings**.
   * **Password**: Enter the app password you created in the previous steps.
5. Click **Save**.

Note: When using an on-premises configuration of Bitbucket, the language does not populate on [entity detail pages](#view-bitbucket-information-on-entity-pages-in-cortex).
{% endtab %}

{% tab title="OAuth" %}
**Configure Cortex with Bitbucket on-premises using OAuth**

{% hint style="info" %}
Scaffolder and Workflow automation are supported with this configuration. See [Registering a Scaffolder template](/streamline/workflows/scaffolder) for setup details.
{% endhint %}

**Prerequisites**

To configure this integration with on-prem OAuth, you must be running a self-hosted Bitbucket instance with Bitbucket Server or Data Center version 7.20 or higher.

**Step 1: Set up an application link in Bitbucket**

1. In your Bitbucket server, navigate to **Settings > System > Application Links > Create Link**.
2. Configure the application link:
   * For the application type, select "External Application."
   * For the direction, select "Incoming."
   * For the redirect URL:
     * Default configuration: Enter the URL of your Cortex instance and `/oauth/internal/bitbucket`.
     * Non-default configuration: Enter the URL of your Cortex instance and `/oauth/internal/bitbucket/{alias}`.
   * For the Permission, select `Projects: Admin` and `Repositories: Admin`.
3. Click **Save**.
4. Copy the client ID and client secret. You will need these in the next steps.

**Step 2: Configure the integration in Cortex**

1. In Cortex, navigate to the [Bitbucket settings page](https://app.getcortexapp.com/admin/integrations/bitbucket).
   * Click **Integrations** from the main nav. Search for and select **Bitbucket**.
2. Click **Add configuration**.
3. For the configuration type, select **On-prem (OAuth)**.

   <div align="left"><figure><img src="/files/fBpwWgXGCYJY5y4CLTxA" alt="" width="270"><figcaption></figcaption></figure></div>
4. Configure the "Add Bitbucket configuration" form:
   * **Account alias**: Enter an alias for the account. Aliases are used to tie service registrations to different configuration accounts.
   * **Host**: Enter your Bitbucket on-prem host, e.g., `https://bitbucket.example.com`.
   * **Client ID**: Enter the client ID you obtained in the previous steps.
   * **Client secret**: Enter the client secret you obtained in the previous steps.
5. Click **Save**.

Note: When using an on-premises configuration of Bitbucket, the language does not populate on [entity detail pages](#view-bitbucket-information-on-entity-pages-in-cortex).
{% endtab %}

{% tab title="Relay" %}
**Configure Bitbucket with Cortex Axon Relay**

{% hint style="info" %}
Scaffolder and Workflow automation are supported when connecting Bitbucket via Axon Relay. See [Registering a Scaffolder template](https://docs.cortex.io/streamline/workflows/scaffolder) for setup details.
{% endhint %}

See [Internally hosted integrations](/ingesting-data-into-cortex/integrations/axon-relay) for instructions. Make sure to follow the Bitbucket-specific instructions for the docker-compose.yml file.
{% endtab %}
{% endtabs %}

Once you save your configuration, you'll see it listed on the integration's settings page in Cortex. If you’ve set everything up correctly, you’ll see the option to **Remove Integration** in Settings.

You can also use the **Test all configurations** button to confirm that the configuration was successful. If your configuration is valid, you’ll see a banner that says “Configuration is valid. If you see issues, please see documentation or reach out to Cortex support.”

**Configure the integration for multiple Bitbucket accounts**[**​**](https://docs.cortex.io/docs/reference/integrations/bitbucket#configure-the-integration-for-multiple-propsintegration-accounts)

The Bitbucket integration has multi-account support. You can add a configuration for each additional by repeating the process above.

Each configuration requires an alias, which Cortex uses to correlate the designated with registrations for various entities. Registrations can also use a default configuration without a listed alias. You can edit aliases and default configurations from the Bitbucket page in your Cortex settings. Select the edit icon next to a given configuration and toggle **Set as default** on. If you only have one configuration, it will automatically be set as the default.

Cortex supports mapping multiple identities for a single user if you have multiple configurations of Bitbucket. See the [Identity mapping](/configure/settings/managing-users/identity-mapping) documentation for more information.

### Limit which Bitbucket projects are used for the integration

If you are a part of multiple projects in Bitbucket but you only want to show repositories for a specific set of projects, you can specify the projects in Cortex:

1. Navigate to the [Bitbucket integration settings page](https://app.getcortexapp.com/admin/settings/bitbucket).
2. Click the pencil icon in the row containing the Bitbucket configuration you want to edit.\\

   <figure><img src="/files/LWbZ1zGMmhrbua9qi6wE" alt="Click the pencil icon to edit the Bitbucket configuration."><figcaption></figcaption></figure>
3. Under **Project names**, select which projects you want to include.\
   ![](/files/MiclIIF1e57JvjA9TxcD)
4. At the bottom of the side panel, click **Save**.

### Use webhooks for GitOps functionality

To use webhooks for GitOps functionality, you need to set a secret token on the [Bitbucket Settings](https://app.getcortexapp.com/admin/settings/bitbucket) page. This helps Cortex identify that the webhook event is valid. Make sure to enter the same secret when configuring the webhook on Bitbucket Server. \\

<figure><img src="/files/LyLOPNZ0Co1bB6V8A6pp" alt=""><figcaption></figcaption></figure>

## How to connect Cortex entities to Bitbucket

### Import entities from Bitbucket

See the [Create services documentation](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/add-services#creating-services) for instructions on importing entities.

### Editing the entity descriptor

**Set repository details**

By specifying the `x-cortex-git` field in your Cortex entity descriptor, you'll be able to see Git information in the entity page, including the top language, recent commits, and top contributors.

```yaml
x-cortex-git:
  bitbucket:
    repository: /
    basepath: myService # optional
    alias: myApp # optional
```

| Field        | Description                                                                                        | Required |
| ------------ | -------------------------------------------------------------------------------------------------- | -------- |
| `repository` | `org/repo` as defined in Bitbucket                                                                 | true     |
| `basepath`   | If the entity is in a monorepo (e.g. in a subdirectory), use this field to define the subdirectory | false    |
| `alias`      | Alias is optional and only relevant if you have opted into multi account support                   | false    |

The value for `repository` should be the *workspace/repo* as defined in Bitbucket.

**Ownership**

You can define the following block in your Cortex entity descriptor to add your Bitbucket teams.

```yaml
x-cortex-owners:
  - type: group
    name: Team Name
    provider: BITBUCKET
    description: This is a description for this Bitbucket team that owns this entity.
```

| Field         | Description                                                    | Required |
| ------------- | -------------------------------------------------------------- | :------: |
| `type`        | Ownership type; must be defined as `group` for Bitbucket teams |   **✓**  |
| `name`        | Bitbucket team name                                            |   **✓**  |
| `provider`    | Name of integration (in this case, `BITBUCKET`)                |   **✓**  |
| `description` | Description for the Bitbucket team                             |          |

### Identity mappings

Cortex maps users' email addresses to discovered Bitbucket accounts, so you never need to define email ownership in an entity descriptor.

You can confirm users' Bitbucket accounts are connected from [Bitbucket identity mappings in settings](/configure/settings/managing-users/identity-mapping).

## Using the Bitbucket integration

### View Bitbucket information on entity pages in Cortex

The Bitbucket integration populates the **Repository** block on an [entity's details page](/ingesting-data-into-cortex/entities-overview/entities/details). For cloud configurations, it also populates the **Language** block. If a Bitbucket team has been defined as the owner for an entity, it will also appear in the Owners block.

<figure><img src="/files/vYrbvmisuYqlr0ElwDqE" alt=""><figcaption></figcaption></figure>

In the **Recent activity** preview, you'll find the recent commits and releases.

#### **Events**

On an entity's **Events** page, you can find all of the commits and releases associated with that entity. Each is hyperlinked to the commit or release page in Bitbucket and includes a timestamp.

#### **CI/CD**

To see pipeline runs for Bitbucket, use the [deploys API](/ingesting-data-into-cortex/entities-overview/entities/deploys) to add deploy information. After doing this, from the **CI/CD > Deploys** page in the entity's sidebar, you will see a history of pipeline runs.

#### **Workflows**

If a Workflow applies to a given entity, any actions you can perform are available under the **Workflows** link in the side panel of an entity.

#### **Repository**

You can access more detailed information pulled from Bitbucket in the **Repository** link in the sidebar. At the top of the repository page, see the repositories associated with that entity. For cloud configurations, you can also see the most-used language in files for that entity. In the **Top contributors** block, you'll find the three users who have contributed the most code and the number of their contributions.

In the **Commits** section, you'll find the 10 most recent commits and metadata about each. Below **Commits** is the **Recent releases** section, which includes the 5 most recent releases.

#### **Packages**

Packages are automatically scraped from your Git repos or they can be submitted via the [packages API](/api/readme/packages). The package file must be in the root of your repository — or, if you're using `basepath`, in the root of the subdirectory — to be scraped by Cortex. You can query an entity's packages in [CQL explorer](https://app.getcortexapp.com/admin/cql-explorer) using `packages()`.

To view packages, click **Packages** in the entity's sidebar.

The following package types are automatically scraped from repositories:

* JavaScript / Node.js: `package.json`, `package-lock.json`, `yarn.lock`, `pnpm-lock.yaml`
* Python: `requirements.txt`, `pipfile.lock`
* .NET (C#): `packages.lock.json`
* Java: `pom.xml`
* Go: `go.sum`

All other files of these types can be added via the [packages API](/api/readme/packages).

### Engineering homepage

{% hint style="info" %}
Due to rate limits, Bitbucket ingestion on the homepage is limited to repositories mapped to a Cortex entity.
{% endhint %}

The Bitbucket integration enables Cortex to pull information about pull requests and work items into the [homepage](/streamline/homepage). You can find your open pull requests and any pull requests assigned to you for review.

Pull requests from Bitbucket are refreshed every 5 minutes.

### Eng Intelligence

{% hint style="info" %}

* Due to rate limits, Bitbucket ingestion in Eng Intelligence is limited to repositories mapped to a Cortex entity.
* When using Bitbucket in Eng Intelligence, it's highly recommended to use the [workspace token configuration](#workspace-token).
  {% endhint %}

[Eng Intelligence](/improve/eng-intelligence) also uses pull request data from Bitbucket to generate metrics:

* Average PR open to close time
* Avg time to first review
* Avg time to approval
* PRs opened
* Weekly PRs merged
* Avg PRs reviewed/week

### Scorecards and CQL

With the Bitbucket integration, you can create Scorecard rules and write CQL queries based on Bitbucket details.

See more examples in the [CQL Explorer](https://app.getcortexapp.com/admin/cql-explorer) in Cortex.

<details>

<summary>Approvals required to merge</summary>

The total number of approvals required to merge a Pull Request into the repository, defaulting to 0 if no approvals are defined.

**Definition:** `git.numOfRequiredApprovals(): Number`

**Example**

In a Scorecard, you can write a rule to encourage at least one approval for each Pull Request:

```
git.numOfRequiredApprovals() >= 1
```

</details>

<details>

<summary>Git repository set</summary>

Check if an entity has a registered Git repository.

**Definition:** `git (==/!=) null: Boolean`

**Example**

In a Scorecard, you can write a rule that detects whether an entity has a Git repository set:

```
git != null
```

</details>

<details>

<summary>Pipeline build success rate</summary>

The percentage of build pipelines that complete successfully. This is calculated against builds on the default branch, for commits in the last 30 days. The calculation is # successful builds / (# successful + # failed). **Definition:** `git.percentBuildSuccess(): Number`

**Example**

In a Scorecard, you can write a rule that requires at least 90% of build runs to be successful:

```
git.percentBuildSuccess() > 0.9
```

</details>

### View integration logs <a href="#still-need-help" id="still-need-help"></a>

{% hint style="info" %}
This feature is available in Cortex cloud.
{% endhint %}

While viewing an integration's settings page, select the **Logs** tab to view error logs from the last 7 days. You can filter the logs list by configuration and by operation (for example, you could filter to view errors surfaced only via Scorecards).

<div align="left" data-with-frame="true"><figure><img src="/files/x8JmoPqXZTJ7YHeFJpOA" alt="The &#x27;Logs&#x27; tab on an integration&#x27;s settings page shows error information over the past 7 days."><figcaption></figcaption></figure></div>

Click into a row to get more information, including time stamp, status code, full error, and request path.

## Background sync

Cortex conducts a background sync of Bitbucket identities every day at 10 a.m. UTC. Repositories are refreshed every day at 2 p.m. UTC.

## Troubleshooting and FAQ

**Rules are failing saying that I don't have file `x`, but I verified that the file exists.**

We always use the default branch for file existence checks. Make sure that the file is present in the default branch.

## Still need help?[​](https://docs.cortex.io/docs/reference/integrations/aws#still-need-help) <a href="#still-need-help" id="still-need-help"></a>

The following options are available to get assistance from the Cortex Customer Engineering team:

* **Email**: <help@cortex.io>, or open a support ticket in the in app Resource Center
* **Slack**: Users with a connected Slack channel will have a workflow added to their account. From here, you can either @CortexTechnicalSupport or add a `:ticket:` reaction to a question in Slack, and the team will respond directly.

Don’t have a Slack channel? Talk with your Customer Success Manager.


# BugSnag

{% hint style="info" %}
Cortex connects to many third-party vendors whose system interfaces frequently change. As a result, integration behavior or configuration steps may shift without notice. If you encounter unexpected issues, check with your system administrator or refer to the vendor's documentation for the most current information. Additionally, integration sync times vary and are subject to scheduling overrides and timing variance.
{% endhint %}

[BugSnag](https://www.bugsnag.com/) is an application stability monitoring platform that provides error tracking and analytics.

Integrating BugSnag with Cortex allows you to:

* [View errors on entity pages](#viewing-bugsnag-errors-on-an-entity) in Cortex, giving you insight into your entity's operational maturity
* Create [Scorecards](#scorecards-and-cql) that include rules related to BugSnag errors

## How to configure BugSnag with Cortex

### Prerequisites

Before getting started:

* Create a [BugSnag auth token](https://bugsnagapiv2.docs.apiary.io/#introduction/authentication) in your [BugSnag account's settings page](https://app.bugsnag.com/settings/my-account) under "My account."
* You must have the `Configure integrations` permission in Cortex.

{% hint style="warning" %}
If you're using a self-hosted instance of BugSnag, you'll need to verify that your Cortex instance is able to reach the BugSnag instance.\
\
We route our requests through a static IP address. Reach out to support at <help@cortex.io> to receive details about our static IP. If you're unable to directly allowlist our static IP, you can route requests through a secondary proxy in your network that has this IP allowlisted and have that proxy route traffic to your BugSnag instance.
{% endhint %}

### Configure the integration in Cortex

1. In Cortex, navigate to the [BugSnag settings page](https://app.getcortexapp.com/admin/integrations/bugsnag).
   * Click **Integrations** from the main nav. Search for and select **BugSnag**.
2. Click **Add configuration**.
3. Configure the integration form:
   * **Auth token**: Enter the auth token you generated in BugSnag.
   * **Organization slug**: Enter your BugSnag organization slug.
     * You can find this in your BugSnag URL, e.g., `https://app.bugsnag.com/organizations/{SLUG}/stability-center`.
   * **Host**: If using a custom BugSnag instance, enter the URL here *without* the API path (e.g., `bugsnag.getcortexapp.com`).
4. Click **Save**.

After saving your configuration, you are redirected to the BugSnag integration settings page in Cortex. In the upper right corner of the page, click **Test configuration** to ensure BugSnag was configured properly.

## How to connect Cortex entities to BugSnag projects

### Discovery

By default, Cortex will use the [Cortex tag](/ingesting-data-into-cortex/entities-overview/entities#cortex-tag) (e.g. `my-entity`) as the "best guess" for BugSnag projects. For example, if your Cortex tag is `my-entity`, then the corresponding project in BugSnag should also be `my-entity`.

If your BugSnag projects don’t cleanly match the [Cortex tag](/ingesting-data-into-cortex/entities-overview/entities#cortex-tag), you can override this in the Cortex entity descriptor.

### Editing the entity descriptor

You can define projects under the `x-cortex-bugsnag` block:

```yaml
x-cortex-bugsnag:
  project: my-project
```

| Field     | Description                    | Required |
| --------- | ------------------------------ | :------: |
| `project` | Project key defined in BugSnag |   **✓**  |

## Using the BugSnag integration

### Viewing BugSnag errors on an entity

Error data will appear on an [entity's details page](/ingesting-data-into-cortex/entities-overview/entities/details). You can find the total number of detected errors and a full list on the **Error tracking** page in the entity's side panel. Error data is fetched live.

Each error in the list will display with an `Error`, `Info`, or `Warning` tag based on the [severity](https://docs.bugsnag.com/product/severity-indicator/#severity) applied to a given error in BugSnag.

### Scorecards and CQL

With the BugSnag integration, you can create Scorecard rules and write CQL queries based on BugSnag projects and issues.

See more examples in the [CQL Explorer](https://app.getcortexapp.com/admin/cql-explorer) in Cortex.

<details>

<summary>Check if BugSnag is set</summary>

Check if an entity has a registered BugSnag project.

**Definition:** `bugsnag (==/!=) null`

**Example**

This expression can be used to write a Scorecard rule to make sure each entity has a registered BugSnag project:

```
bugsnag != null
```

This is also a good way to double-check that the integration is synced and reporting frequently.

</details>

<details>

<summary>Number of issues</summary>

Count all unresolved issues in BugSnag or counts number of issues for a given query. By default, will count all unresolved issues.

**Definition:** `bugsnag.numOfIssues(query: Text | Null)`

**Example**

For a Scorecard focused on operational maturity, you can pull in error data from BugSnag to make sure your entities have no or few errors.

```
bugsnag.numOfIssues() < 2
```

To set a more specific standard, you can also create a rule based on a [filter](https://docs.bugsnag.com/product/custom-filters/).

```
bugsnag.numOfIssues("filters[error.status][][type]=example")
```

</details>

### View integration logs <a href="#still-need-help" id="still-need-help"></a>

{% hint style="info" %}
This feature is available in Cortex cloud.
{% endhint %}

While viewing an integration's settings page, select the **Logs** tab to view error logs from the last 7 days. You can filter the logs list by configuration and by operation (for example, you could filter to view errors surfaced only via Scorecards).

<div align="left" data-with-frame="true"><figure><img src="/files/x8JmoPqXZTJ7YHeFJpOA" alt="The &#x27;Logs&#x27; tab on an integration&#x27;s settings page shows error information over the past 7 days."><figcaption></figcaption></figure></div>

Click into a row to get more information, including time stamp, status code, full error, and request path.

## Still need help?[​](https://docs.cortex.io/docs/reference/integrations/aws#still-need-help) <a href="#still-need-help" id="still-need-help"></a>

The following options are available to get assistance from the Cortex Customer Engineering team:

* **Email**: <help@cortex.io>, or open a support ticket in the in app Resource Center
* **Slack**: Users with a connected Slack channel will have a workflow added to their account. From here, you can either @CortexTechnicalSupport or add a `:ticket:` reaction to a question in Slack, and the team will respond directly.

Don’t have a Slack channel? Talk with your Customer Success Manager.


# Buildkite

{% hint style="info" %}
Cortex connects to many third-party vendors whose system interfaces frequently change. As a result, integration behavior or configuration steps may shift without notice. If you encounter unexpected issues, check with your system administrator or refer to the vendor's documentation for the most current information. Additionally, integration sync times vary and are subject to scheduling overrides and timing variance.
{% endhint %}

[Buildkite](https://buildkite.com/) is a continuous integration and delivery platform that enablers users to run fast, secure, and scalable pipelines on their own infrastructure.

Integrating Buildkite with Cortex allows you to:

* Pull in metrics about your builds and pipelines
* Create [Scorecards](#scorecards-and-cql) that track progress and drive alignment on projects involving your Buildkite pipelines

## How to configure Buildkite with Cortex

### Prerequisites

Before getting started:

* Create a [Buildkite API access token](https://buildkite.com/docs/apis/managing-api-tokens) with read-only permissions for pipelines and builds.
  * You must be a member of a Buildkite organization to generate and use an access token for it.

### Configure the integration in Cortex

1. In Cortex, navigate to the [Buildkite settings page](https://app.getcortexapp.com/admin/integrations/buildkite).
   * Click **Integrations** from the main nav. Search for and select **Buildkite**.
2. Configure the Buildkite integration form:
   * **API token**: Enter your Buildkite API token.
   * **Organizational slug**: Enter the slug for your Buildkite organization.
     * This can be found in your organization's Buildkite settings, or at the end of your Buildkite URL after navigating to **Pipelines**.
3. Click **Save**.

## How to connect Cortex entities to Buildkite

### Discovery

By default, Cortex will use the [Cortex tag](/ingesting-data-into-cortex/entities-overview/entities#cortex-tag) (e.g. `my-entity`) for your Buildkite pipeline. For example, if your Cortex tag is `my-pipeline`, then the corresponding pipeline tag in Buildkite should also be `my-pipeline`.

Cortex will also use the the GitHub, GitLab, Bitbucket, or Azure DevOps repository to connect entities to Buildkite pipelines. For example, if the GitHub repo associated with your Buildkite pipeline is `my-org/repo`, then entities in Cortex that also live in `my-org/repo` will populate with details from that pipeline.

### Editing the entity descriptor

You can add Buildkite pipelines to an entity by defining the pipeline slug or tags with one of the following blocks in the entity descriptor:

```yaml
x-cortex-ci-cd:
  buildkite:
    pipelines:
    - slug: my-buildkite-pipeline-slug-1
    - slug: my-buildkite-pipeline-slug-2
```

| Field  | Description                     | Required |
| ------ | ------------------------------- | :------: |
| `slug` | Slug for the Buildkite pipeline |   **✓**  |

```yaml
x-cortex-ci-cd:
  buildkite:
    tags:
    - tag: my-buildkite-tag-1
    - tag: my-buildkite-tag-2
```

| Field | Description                    | Required |
| ----- | ------------------------------ | :------: |
| `tag` | Tag for the Buildkite pipeline |   **✓**  |

The slug for your pipeline can be found in the Buildkite URL for a given pipeline (e.g., `https://buildkite.com//`).

## Using the Buildkite integration

#### Entity pages

Once the Buildkite integration is established, Cortex will automatically pull in pipeline data to an entity's page. You can access this data from the **CI/CD** page in the entity's side panel.

You can find a list of pipeline runs for each pipeline linked to a given entity on this page:

* Pipeline slug/tag
* Action (e.g. "scheduled build")
* Timestamp
* Branch
* State

The [state](https://buildkite.com/docs/pipelines/notifications#build-states) for a build will appear as a tag next to the pipeline slug/tag (e.g. `canceled`, `passed`, or `failed`).

### Scorecards and CQL

With the Buildkite integration, you can create Scorecard rules and write CQL queries based on Buildkite pipelines.

See more examples in the [CQL Explorer](https://app.getcortexapp.com/admin/cql-explorer) in Cortex.

<details>

<summary>Check if Buildkite pipeline(s) are set</summary>

Check if entity has registered Buildkite pipelines in its entity descriptor.

**Definition:** `buildkite (==/!=) null`

**Example**

For a Scorecard focused on production readiness, you can pull in data from Buildkite to make sure that entities belong to a CI/CD pipeline.

```
buildkite != null
```

</details>

<details>

<summary>Get Buildkite build(s)</summary>

Gets pipelines and builds that meet given filter criteria.

* Build criteria:
  * Branch
  * Commit
  * Created at
  * ID
  * Message
  * Number
  * Pipeline
  * State
* Pipeline criteria:
  * Description
  * Git repository
  * ID
  * Name
  * Slug
  * Tags

States include CANCELED, PASSED, and FAILED.

**Definition**: `buildkite.builds()`

**Example**

If you're building a Scorecard with an emphasis on operational maturity, you could set a rule to make sure not only that entities belong to a pipeline, but that the pipeline is functioning as expected.

```
buildkite.builds(states["passed"]).length >=1
```

</details>

<details>

<summary>Get Buildkite pipelines</summary>

Get all Buildkite pipelines associated with the entity: Description, Git repository, ID, Name, Slug, Tags.

**Definition**: `buildkite.pipelines()`

**Example**

A production readiness Scorecard can use this expression in a rule confirming that there are pipelines linked to a specific repository:

```
buildkite.pipelines().any((pipeline) => pipeline.gitRepository = )
```

</details>

### View integration logs <a href="#still-need-help" id="still-need-help"></a>

{% hint style="info" %}
This feature is available in Cortex cloud.
{% endhint %}

While viewing an integration's settings page, select the **Logs** tab to view error logs from the last 7 days. You can filter the logs list by configuration and by operation (for example, you could filter to view errors surfaced only via Scorecards).

<div align="left" data-with-frame="true"><figure><img src="/files/x8JmoPqXZTJ7YHeFJpOA" alt="The &#x27;Logs&#x27; tab on an integration&#x27;s settings page shows error information over the past 7 days."><figcaption></figcaption></figure></div>

Click into a row to get more information, including time stamp, status code, full error, and request path.

## Still need help?[​](https://docs.cortex.io/docs/reference/integrations/aws#still-need-help) <a href="#still-need-help" id="still-need-help"></a>

The following options are available to get assistance from the Cortex Customer Engineering team:

* **Email**: <help@cortex.io>, or open a support ticket in the in app Resource Center
* **Slack**: Users with a connected Slack channel will have a workflow added to their account. From here, you can either @CortexTechnicalSupport or add a `:ticket:` reaction to a question in Slack, and the team will respond directly.

Don’t have a Slack channel? Talk with your Customer Success Manager.


# Checkmarx

{% hint style="info" %}
Cortex connects to many third-party vendors whose system interfaces frequently change. As a result, integration behavior or configuration steps may shift without notice. If you encounter unexpected issues, check with your system administrator or refer to the vendor's documentation for the most current information. Additionally, integration sync times vary and are subject to scheduling overrides and timing variance.
{% endhint %}

## Overview

Checkmarx is an automated application security platform that checks source code for security vulnerabilities and compliance issues. Integrate Cortex with Checkmarx to drive insight into the vulnerabilities detected on your entities.

This integration is supported for [Checkmarx Static Application Security Testing (SAST)](https://checkmarx.com/cxsast-source-code-scanning/).

## How to configure Checkmarx with Cortex

### Prerequisites

Before getting started, create a user with access to the `sast_rest_api` scope.

{% hint style="warning" %}
If you're using a self-hosted instance of Checkmarx, you'll need to verify that your Cortex instance is able to reach the Checkmarx instance.\
\
We route our requests through a static IP address. Reach out to support at <help@cortex.io> to receive details about our static IP. If you're unable to directly allowlist our static IP, you can route requests through a secondary proxy in your network that has this IP allowlisted and have that proxy route traffic to your Checkmarx instance.
{% endhint %}

### Configure the integration in Cortex

1. In Cortex, navigate to the [Checkmarx settings page](https://app.getcortexapp.com/admin/integrations/checkmarx).
   * Click **Integrations** from the main nav. Search for and select **Checkmarx**.
2. Click **Add configuration**.
3. Configure the Checkmarx integration form:
   * **Username** and **Password**: Enter the username and password for the user with access to `sast_rest_api`.
   * **Host**: Enter the full URL of your Checkmarx instance.
4. Click **Save**.

## How to connect Cortex entities to Checkmarx

### Discovery

By default, Cortex will use your associated Git repository (e.g. `repo-name`) or the service tag as the "best guess" for the Checkmarx project name.

If your repository and entity names don’t cleanly match the Checkmarx CxSAST project names, or if you have multiple Checkmarx projects for a service, you can add a Checkmarx project ID (recommended) or a Checkmarx project name in the Cortex entity descriptor.

### Editing the entity descriptor

We recommend using the project ID as it is a unique identifier across projects.

Example using project IDs:

```yaml
x-cortex-checkmarx:
  projects:
    - projectId: 1234
    - projectId: 2345
```

Example using both project IDs and names:

```yaml
x-cortex-checkmarx:
  projects:
    - projectName: My Cool Project
    - projectId: 1234
```

## Using the Checkmarx integration

#### Entity pages

Once the integration is established, vulnerabilities pulled from Checkmarx will be available for each entity in the **Code and Security** block in the **Overview** tab.

While viewing an entity, click **Code & security > Checkmarx**. On this page, view the number of vulnerabilities per severity and a link directly to your Checkmarx instance.

### Scorecards and CQL

With the Checkmarx integration, you can create Scorecard rules and write CQL queries based on Checkmarx details.

See more examples in the [CQL Explorer](https://app.getcortexapp.com/admin/cql-explorer) in Cortex.

<details>

<summary>Check if Checkmarx project is set</summary>

Check if entity has a registered Checkmarx project in its entity descriptor. If there is a Checkmarx project name, we will try and make sure that the project exists in Checkmarx.

**Definition:** `checkmarx (==/!=) null: Boolean`

**Example**

In a Scorecard, you can write a rule to check whether an entity has a Checkmarx project set:

```
checkmarx != null
```

</details>

<details>

<summary>Checkmarx scan risk</summary>

Get the maximum scan risk among the entity's project's latest scans

**Definition:** `checkmarx.sastScanRisk(): Number`

**Example**

In a Scorecard, you can write a rule to verify that an entity has no Checkmarx projects where the latest scan risk is higher than 35:

```
checkmarx.sastScanRisk() < 35
```

</details>

<details>

<summary>Number of Checkmarx vulnerabilities</summary>

Get the count of all vulnerabilities for an entity's Checkmarx project's last scan

**Definition:** `checkmarx.numOfVulnerabilities(): Number`

**Example**

In a Scorecard, you can write a rule to verify that an entity has no vulnerabilities with a severity of `HIGH`:

```
checkmarx.numOfVulnerabilities(severity=["High"]) < 1
```

Verify that an entity has less than 5 vulnerabilities total:

```
checkmarx.numOfVulnerabilities() < 5
```

</details>

### View integration logs <a href="#still-need-help" id="still-need-help"></a>

{% hint style="info" %}
This feature is available in Cortex cloud.
{% endhint %}

While viewing an integration's settings page, select the **Logs** tab to view error logs from the last 7 days. You can filter the logs list by configuration and by operation (for example, you could filter to view errors surfaced only via Scorecards).

<div align="left" data-with-frame="true"><figure><img src="/files/x8JmoPqXZTJ7YHeFJpOA" alt="The &#x27;Logs&#x27; tab on an integration&#x27;s settings page shows error information over the past 7 days."><figcaption></figcaption></figure></div>

Click into a row to get more information, including time stamp, status code, full error, and request path.

## FAQs and troubleshooting

**Does Cortex support integrating with Checkmarx One?**

No, Cortex does not currently support Checkmarx one. Only Checkmarx SAST is supported for this integration.

## Still need help?[​](https://docs.cortex.io/docs/reference/integrations/aws#still-need-help) <a href="#still-need-help" id="still-need-help"></a>

The following options are available to get assistance from the Cortex Customer Engineering team:

* **Email**: <help@cortex.io>, or open a support ticket in the in app Resource Center
* **Slack**: Users with a connected Slack channel will have a workflow added to their account. From here, you can either @CortexTechnicalSupport or add a `:ticket:` reaction to a question in Slack, and the team will respond directly.

Don’t have a Slack channel? Talk with your Customer Success Manager.


# CircleCI

{% hint style="info" %}
Cortex connects to many third-party vendors whose system interfaces frequently change. As a result, integration behavior or configuration steps may shift without notice. If you encounter unexpected issues, check with your system administrator or refer to the vendor's documentation for the most current information. Additionally, integration sync times vary and are subject to scheduling overrides and timing variance.
{% endhint %}

[CircleCI](https://circleci.com/) is continuous integration and continuous delivery platform that can be used to implement DevOps best practices.

Integrating CircleCI with Cortex allows you to:

* [View information about CircleCI workflows and pipelines on entity pages](#viewing-circleci-information-on-entity-pages) in Cortex
* Create [Scorecards](/standardize/scorecards) that track progress and drive alignment on projects involving your CircleCI data

## How to configure CircleCI with Cortex

### Prerequisites

Before getting started:

* Create a [CircleCI API token](https://circleci.com/docs/managing-api-tokens/).

**Self-hosted CircleCI instances**

If you’re using a self-hosted instance of CircleCI, you’ll need to verify that your Cortex instance is able to reach the CircleCI instance.\
\
We route our requests through a static IP address. Reach out to support at <help@cortex.io> to receive details about our static IP. If you're unable to directly allowlist our static IP, you can route requests through a secondary proxy in your network that has this IP allowlisted and have that proxy route traffic to your CircleCI instance.

### Configure the integration in Cortex

1. In Cortex, navigate to the [CircleCI settings page](https://app.getcortexapp.com/admin/integrations/circleci).
   * Click **Integrations** from the main nav. Search for and select **CircleCI**.
2. Click **Add configuration**.
3. Configure the integration form:
   * **Account alias**: Enter an alias for this integration, used to tie entity registrations to different configurations.
   * **API token**: Enter the value of the API token you created in CircleCI.
   * **Host**: Enter the URL for your CircleCI instance if self-hosted, e.g., `https://cortex.circleci.com`
4. Click **Save**.

**Configure the integration for multiple CircleCI accounts**[**​**](https://docs.cortex.io/docs/reference/integrations/circleci#configure-the-integration-for-multiple-propsintegration-accounts)

The CircleCI integration has multi-account support. You can add a configuration for each additional by repeating the process above.

Each configuration requires an alias, which Cortex uses to correlate the designated with registrations for various entities. Registrations can also use a default configuration without a listed alias. You can edit aliases and default configurations from the CircleCI page in your Cortex settings. Select the edit icon next to a given configuration and toggle **Set as default** on. If you only have one configuration, it will automatically be set as the default.

## How to connect Cortex entities to CircleCI

### Editing the entity descriptor

You can define CircleCI projects in an [entity's YAML descriptor](/ingesting-data-into-cortex/entities-overview/entities#defining-entities-via-yaml-file). Add its project slug under the `x-cortex-circle-ci` block:

```yaml
x-cortex-circle-ci:
  projects:
    - projectSlug: circleci-projectslug # projectslug in CircleCI
      alias: circleci-alias # alias is optional and only relevant if you have opted into multi account support
```

## Using the CircleCI integration

### Viewing CircleCI information on entity pages

When an entity has a CircleCI project defined in its YAML file, you will see metric and pipeline details on an [entity's details page](/ingesting-data-into-cortex/entities-overview/entities/details). Click **CI/CD > CircleCI** in the entity's sidebar to see this information.

### Scorecards and CQL

With the CircleCI integration, you can create Scorecard rules and write CQL queries based on CircleCI metrics and pipelines.

See more examples in the [CQL Explorer](https://app.getcortexapp.com/admin/cql-explorer) in Cortex.

<details>

<summary>Check for CircleCI flaky tests</summary>

Get all Circle CI flaky tests associated with the entity.

**Definition**: `circleci.flakyTests()`

**Example**

You could create a Scorecard with a rule that verifies no flaky tests:

```
circleci.flakyTests().length == 0
```

</details>

<details>

<summary>Get Circle CI projects</summary>

Get all Circle CI projects associated with the entity.

**Definition**: `circleci.projects()`

**Example**

You could also create a rule that checks for a success rate over 90%:

```
circleci.projects().all((project) => project.metrics.successRate > 0.9) == true
```

</details>

### View integration logs <a href="#still-need-help" id="still-need-help"></a>

{% hint style="info" %}
This feature is available in Cortex cloud.
{% endhint %}

While viewing an integration's settings page, select the **Logs** tab to view error logs from the last 7 days. You can filter the logs list by configuration and by operation (for example, you could filter to view errors surfaced only via Scorecards).

<div align="left" data-with-frame="true"><figure><img src="/files/x8JmoPqXZTJ7YHeFJpOA" alt="The &#x27;Logs&#x27; tab on an integration&#x27;s settings page shows error information over the past 7 days."><figcaption></figcaption></figure></div>

Click into a row to get more information, including time stamp, status code, full error, and request path.

## Still need help?[​](https://docs.cortex.io/docs/reference/integrations/aws#still-need-help) <a href="#still-need-help" id="still-need-help"></a>

The following options are available to get assistance from the Cortex Customer Engineering team:

* **Email**: <help@cortex.io>, or open a support ticket in the in app Resource Center
* **Slack**: Users with a connected Slack channel will have a workflow added to their account. From here, you can either @CortexTechnicalSupport or add a `:ticket:` reaction to a question in Slack, and the team will respond directly.

Don’t have a Slack channel? Talk with your Customer Success Manager.


# ClickUp

{% hint style="info" %}
Cortex connects to many third-party vendors whose system interfaces frequently change. As a result, integration behavior or configuration steps may shift without notice. If you encounter unexpected issues, check with your system administrator or refer to the vendor's documentation for the most current information. Additionally, integration sync times vary and are subject to scheduling overrides and timing variance.
{% endhint %}

[ClickUp](https://clickup.com/) is a project management tool that combines tasks, document collaboration, and issue management in a single platform.

Integrating ClickUp with Cortex allows you to:

* View task information directly on [entity pages](#entity-pages) in Cortex
* Create ClickUp tasks based on Initiatives directly from Cortex
* Map ClickUp identities to users in Cortex
* View open ClickUp tasks in the [dev homepage](#dev-homepage)
* Create [Scorecards](#scorecards-and-cql) that track progress and drive alignment on projects involving your ClickUp tasks

## How to configure ClickUp with Cortex

### Prerequisites

Before getting started:

* Create a [ClickUp personal API token](https://clickup.com/api/developer-portal/authentication/#generate-your-personal-api-token).

### Configure the integration in Cortex

1. In Cortex, navigate to the [ClickUp settings page](https://app.getcortexapp.com/admin/integrations/clickup).
   * Click **Integrations** from the main nav. Search for and select **ClickUp**.
2. Click **Add configuration**.
3. Configure the ClickUp integration form:
   * **API token**: Enter your ClickUp API token.
4. Click **Save**.

If you’ve set everything up correctly, you’ll see the option to **Remove Integration** in settings.

You can also use the **Test configuration** button to confirm that the configuration was successful. If your configuration is valid, you’ll see a banner that says “Configuration is valid. If you see issues, please see documentation or reach out to Cortex support.”

Note that mapping options will not appear in Cortex for users who have not finished user registration in ClickUp. If a user is partially registered, Cortex will filter them out of the mapping page.

## How to connect Cortex entities to ClickUp

### Auto discovery of spaces, folders, and tags

By default, Cortex will use the [Cortex tag](/ingesting-data-into-cortex/entities-overview/entities#cortex-tag) (e.g. `my-entity`) as the "best guess" for ClickUp space, folder, or tag. For example, if your Cortex tag is `my-entity`, then the corresponding space, folder, or tag in ClickUp should also be `my-entity`.

If your ClickUp space, folder, or tag don’t cleanly match the Cortex tag, you can override this in the Cortex entity descriptor.

### Editing the entity descriptor

You can map any number of ClickUp spaces, folders, and tags to a Cortex entity. Spaces and folders can be mapped by using either ID or name.

You can find your folder ID or space ID in your ClickUp URL: `https://app.clickup.com/:workspace_id/v/f/:folder_id/:space_id`.

**Mapping spaces by ID or name**

When mapping spaces, you can use the ID or name for the space.

```yaml
x-cortex-issues:
  clickup:
    spaces:
      - identifier: 123456789
        identifierType: ID
```

```yaml
x-cortex-issues:
  clickup:
    spaces:
      - identifier: My Space
        identifierType: NAME
```

These blocks share the same fields:

| Field            | Description                                            | Required |
| ---------------- | ------------------------------------------------------ | :------: |
| `spaces`         | Denotes that mapping should be based on ClickUp spaces | **true** |
| `identifier`     | Identifier for the space; either the full ID or name   | **true** |
| `identifierType` | Type of identifier; either `ID` or `NAME`              | **true** |

**Mapping folders by ID or name**

When mapping folders, you can use the ID or name for the folder.

```yaml
x-cortex-issues:
  clickup:
    folders:
      - identifier: 123456789
        identifierType: ID
```

```yaml
x-cortex-issues:
  clickup:
    folders:
      - identifier: my-folder
        identifierType: NAME
```

| Field            | Description                                            | Required |
| ---------------- | ------------------------------------------------------ | :------: |
| `folders`        | Denotes that mapping should be based on ClickUp folder | **true** |
| `identifier`     | Identifier for the folder; either the full ID or name  | **true** |
| `identifierType` | Type of identifier; either `ID` or `NAME`              | **true** |

**Mapping by tags**

Cortex also supports mapping entities to ClickUp [tags](https://help.clickup.com/hc/en-us/articles/6304382595991-Manage-task-tags).

```yaml
x-cortex-issues:
  clickup:
    tags:
      - name: tag a
      - name: tag b
      - name: tag c
```

| Field     | Description                                          | Required |
| --------- | ---------------------------------------------------- | :------: |
| `folders` | Denotes that mapping should be based on ClickUp tags | **true** |
| `name`    | Name for the tag                                     | **true** |

### Specify a list for Initiative issues

You can also specify a ClickUp list to store all issues created via Cortex Initiatives. If `Use list defined in entity YAML` is **toggled on** in the Initiative issue creation form, Cortex will automatically create tasks in the specified list for a given entity.

If a list is not specified in an entity's YAML and `Use list defined in entity YAML` option is **toggled on** in the initiative issue creation form, Cortex will attempt to create a list in the mapped space or folder above.

Define one of these following blocks in an entity descriptor to specify a list for Initiative issues.

**Specify list by ID**

```yaml
x-cortex-issues:
    clickup:
      initiativesList:
        id: 12345
```

| Field             | Description         | Required |
| ----------------- | ------------------- | :------: |
| `initiativesList` | Denotes that Cortex | **true** |
| `name`            | Name for the tag    | **true** |

**Specify list by name**

```yaml
x-cortex-issues:
    clickup:
      initiativesList:
        name: Cortex Initiative Issues
```

### Identity mappings

Cortex maps email addresses in your ClickUp instance to email addresses that belong to team members in Cortex. When [identity mapping](/configure/settings/managing-users/identity-mapping) is set up, users will be able to see their personal on-call status from the developer homepage.

Note that mapping options will not appear in Cortex for users who have not finished user registration in ClickUp. If a user is partially registered, Cortex will filter them out of the mapping page.

## Using the ClickUp integration

### Entity pages

**Integrations - ClickUp**

Tasks detected from your ClickUp instance will populate on the **Issue tracking** page in the entity's sidebar. Each row will show the following information (when available in ClickUp):

* Task name (hyperlinked to task in ClickUp)
* Project
* Assignees
* Priority
* Created at
* Due date

### Initiatives

Initiatives allow you to set deadlines for specific rules or a set of rules in a given Scorecard and send notifications to users about upcoming due dates.

From the Issues tab of an Initiative, you can automatically [create a ClickUp task from a failing rule](#create-a-task-from-an-initiative-issue).

### Dev homepage

The ClickUp integration enables Cortex to pull information about tasks into the Dev homepage. You can find open tasks assigned to you under the [Issues tab](https://app.getcortexapp.com/admin/home?activeTab=Issues).

Issues are refreshed every 5 minutes, or you can click **Refresh ClickUp tasks** to manually refresh issues.

### Scorecards and CQL

With the ClickUp integration, you can create Scorecard rules and write CQL queries based on ClickUp tasks.

See more examples in the [CQL Explorer](https://app.getcortexapp.com/admin/cql-explorer) in Cortex.

<details>

<summary>List of ClickUp tasks</summary>

Get ClickUp tasks meeting the given filter criteria.

* Assignees
* Created at
* Creator
* Due date
* Folder
* Priority
  * "Urgent", "High", "Normal," and "Low"
* Status
* Tags
* Task name

Statuses are dependent on your own ClickUp configured statuses. Closed tasks are filtered out by default.

**Definition:** `clickup.tasks()`

**Examples**

To evaluate the maturity of an entity in a Scorecard, you can use this expression to make sure it has fewer than five unassigned ClickUp tasks:

```
clickup.tasks().filter((task) => task.assignees.length < 1).length < 5
```

You can also query for entities that don't have any urgent ClickUp tasks with a "security" tag:

```
clickup.tasks(priorities=["Urgent"], tags=["security"]).length == 0
```

</details>

### View integration logs <a href="#still-need-help" id="still-need-help"></a>

{% hint style="info" %}
This feature is available in Cortex cloud.
{% endhint %}

While viewing an integration's settings page, select the **Logs** tab to view error logs from the last 7 days. You can filter the logs list by configuration and by operation (for example, you could filter to view errors surfaced only via Scorecards).

<div align="left" data-with-frame="true"><figure><img src="/files/x8JmoPqXZTJ7YHeFJpOA" alt="The &#x27;Logs&#x27; tab on an integration&#x27;s settings page shows error information over the past 7 days."><figcaption></figcaption></figure></div>

Click into a row to get more information, including time stamp, status code, full error, and request path.

## Create a task from an Initiative issue

Initiatives allow you to set deadlines for specific rules or a set of rules in a given Scorecard and send notifications to users about upcoming due dates. You can create a ClickUp task from a failing rule in an Initiative. Learn more in [Creating issues based on Initiatives](/improve/initiatives/issue-config).

The issue configuration will apply to all entities that meet the filter criteria. Once an entity is passing the rule, Cortex will automatically close the associated ticket.

## Background sync

Cortex conducts a background sync of ClickUp identities every day at 10 a.m. UTC. Pull requests and issues are refreshed every 5 minutes.

## Still need help?[​](https://docs.cortex.io/docs/reference/integrations/aws#still-need-help) <a href="#still-need-help" id="still-need-help"></a>

The following options are available to get assistance from the Cortex Customer Engineering team:

* **Email**: <help@cortex.io>, or open a support ticket in the in app Resource Center
* **Slack**: Users with a connected Slack channel will have a workflow added to their account. From here, you can either @CortexTechnicalSupport or add a `:ticket:` reaction to a question in Slack, and the team will respond directly.

Don’t have a Slack channel? Talk with your Customer Success Manager.


# Codecov

{% hint style="info" %}
Cortex connects to many third-party vendors whose system interfaces frequently change. As a result, integration behavior or configuration steps may shift without notice. If you encounter unexpected issues, check with your system administrator or refer to the vendor's documentation for the most current information. Additionally, integration sync times vary and are subject to scheduling overrides and timing variance.
{% endhint %}

[Codecov](https://about.codecov.io/) is a code coverage reporting platform that that monitors how much of your code has been tested and validated. Codecov analytics can be used to drive visibility into your microservice architecture and understand coverage trends over time.

Integrating Cortex with Codecov allows you to:

* View code coverage details for entities directly in Cortex
* Create [Scorecards](#scorecards-and-cql) that track progress and drive alignment on projects involving your Codecov code coverage metrics

## How to configure Codecov with Cortex

### Prerequisites

Before getting started:

* Create a [Codecov access token](https://docs.codecov.io/reference#usagen).

### Configure the integration in Cortex

1. In Cortex, navigate to the [Codecov settings page](https://app.getcortexapp.com/admin/integrations/codecov).
   * Click **Integrations** from the main nav. Search for and select **Codecov**.
2. Click **Add configuration**.
3. Configure the Codecov integration form:
   * **API token**: Enter your Codecov access token.
   * **Host**: If you're using a custom Codecov instance, enter your host URL.
     * Make sure to enter the URL **without** the API path (e.g., `https://codecov.getcortexapp.com`).
4. Click **Save**.

## How to connect Cortex entities to Codecov

### Auto discovery of Codecov projects

Cortex will use the GitHub, GitLab, Bitbucket, or Azure DevOps repository as the "best guess" for the corresponding Codecov project, since Codecov projects are connected to repositories. For example, if the GitHub repo associated with your Codecov instance is `my-org/repo`, then the entities in Cortex should also be associated with `my-org/repo`.

You can find the repository for a given entity in its YAML, defined in a block like the one below:

```yaml
x-cortex-git:
  github:
    repository: cortexapps/sample-repo
```

If the Codecov project you want to associate isn't the same as the repository, you can override this in the Cortex entity descriptor.

{% hint style="warning" %}
While Cortex uses the [Cortex tag](/ingesting-data-into-cortex/entities-overview/entities#cortex-tag) for discovery with many integrations, the **repository** is used for Codecov projects.
{% endhint %}

### Editing the entity descriptor

```yaml
x-cortex-static-analysis:
  codecov:
    owner: org-name
    repo: my-project
    provider: AZURE_DEVOPS | BITBUCKET | BITBUCKET_SERVER | GITHUB | GITHUB_ENTERPRISE | GITLAB | GITLAB_ENTERPRISE
    flag: flag
```

| Field      | Description                                          | Required |
| ---------- | ---------------------------------------------------- | :------: |
| `owner`    | Name of the Git organization                         |   **✓**  |
| `repo`     | Git repository (without the organization)            |   **✓**  |
| `provider` | One of the Git providers in the sample YAML          |   **✓**  |
| `flag`     | Pulls from isolated and categorized coverage reports |          |

The value for `repo` should be the **full repository** because Codecov maps projects by repo.

**Flags**

Codecov's [flags](https://docs.codecov.com/docs/flags) are used to categorize coverage reports for various features and tests in a given project. Flags allow you to set different statistics for different areas of your code base. For example, if you have a monorepo with multiple unique projects, you can use Codecov flags to evaluate each project with different test coverage metrics.

To pull flags into Cortex, define the `flag` line in the [entity descriptor block](#editing-the-entity-descriptor).

{% hint style="warning" %}
If you choose to configure with flags, discovery will be disabled; you would need to define the `owner`, `repo`, and `provider` lines.
{% endhint %}

## Using the Codecov integration

#### Entity pages

With the Codecov integration, you can find code coverage details on an entity's details page as long as that entity is associated with a repo linked to your Codecov instance.

Click **Code & security** in the entity's sidebar to see the code coverage for that entity.

### Scorecards and CQL

With the Codecov integration, you can create Scorecard rules and write CQL queries based on Codecov code coverage metrics.

See more examples in the [CQL Explorer](https://app.getcortexapp.com/admin/cql-explorer) in Cortex.

<details>

<summary>Code coverage</summary>

Code coverage for an entity's Git repository (out of 100)

**Definition:** `codecov.codeCoverage()`

**Example**

For a Scorecard focused on development maturity, you can set a rule to make sure code coverage for a given entity is at least 95%:

```
codecov.codeCoverage() >= 95
```

Set a threshold that is both challenging and realistic so there's an incentive for developers to improve.

</details>

{% hint style="success" %}
Setting up a rule based on code coverage can serve as a secondary check to confirm an entity is synced with Codecov and reporting frequently.
{% endhint %}

### View integration logs <a href="#still-need-help" id="still-need-help"></a>

{% hint style="info" %}
This feature is available in Cortex cloud.
{% endhint %}

While viewing an integration's settings page, select the **Logs** tab to view error logs from the last 7 days. You can filter the logs list by configuration and by operation (for example, you could filter to view errors surfaced only via Scorecards).

<div align="left" data-with-frame="true"><figure><img src="/files/x8JmoPqXZTJ7YHeFJpOA" alt="The &#x27;Logs&#x27; tab on an integration&#x27;s settings page shows error information over the past 7 days."><figcaption></figcaption></figure></div>

Click into a row to get more information, including time stamp, status code, full error, and request path.

## Still need help?[​](https://docs.cortex.io/docs/reference/integrations/aws#still-need-help) <a href="#still-need-help" id="still-need-help"></a>

The following options are available to get assistance from the Cortex Customer Engineering team:

* **Email**: <help@cortex.io>, or open a support ticket in the in app Resource Center
* **Slack**: Users with a connected Slack channel will have a workflow added to their account. From here, you can either @CortexTechnicalSupport or add a `:ticket:` reaction to a question in Slack, and the team will respond directly.

Don’t have a Slack channel? Talk with your Customer Success Manager.


# Coralogix

{% hint style="info" %}
Cortex connects to many third-party vendors whose system interfaces frequently change. As a result, integration behavior or configuration steps may shift without notice. If you encounter unexpected issues, check with your system administrator or refer to the vendor's documentation for the most current information. Additionally, integration sync times vary and are subject to scheduling overrides and timing variance.
{% endhint %}

## Overview

[Coralogix](https://coralogix.com/) is an observability and security platform. Integrate Cortex with Coralogix to drive insights into alerts.

After setting up the integration, relevant alerts from Coralogix will appear in your entity pages. While viewing an entity, click **Integrations > Coralogix** in its sidebar to view the list of alerts.

## How to configure Coralogix with Cortex

### Prerequisites

Before getting started, generate a [Coralogix API key](https://coralogix.com/docs/alerts-api/#api-access).

### Step 1: Configure the integration in Cortex

1. In Cortex, navigate to the [Coralogix settings page](https://app.getcortexapp.com/admin/integrations/coralogix)
   * Click **Integrations** from the main nav. Search for and select **Coralogix**.
2. Click **Add configuration**.
3. Configure the Coralogix integration form:
   * **Account alias**: Enter your account alias.
   * **API key**: Enter your Coralogix API key.
   * **Region**: Select your region.
4. Click **Save**.

## How to connect Cortex entities to Coralogix

### Discovery

By default, Cortex will use the entity name or [Cortex tag](/ingesting-data-into-cortex/entities-overview/entities#cortex-tag) (e.g. `my-service`) as the "best guess" for the Coralogix alert application name. For example, if your entity name is "My Service" and your Cortex tag is “my-service”, then the corresponding application name in Coralogix should be “My Service” or "my-service".

If your Coralogix application names don’t cleanly match the Cortex tag, you can override this in the Cortex entity descriptor.

### Editing the entity descriptor

Coralogix alerts can be listed in the Catalog under the `Coralogix` section. We support application names in the YAML for pulling Coralogix alerts.

```yaml
info:
  x-cortex-coralogix:
    applications:
    - applicationName: my-app # application name tied to alert
      alias: my-alias # alias is optional and only relevant if you have opted into multi account support
```

## Using the Coralogix integration

### Scorecards and CQL

With the Coralogix integration, you can create Scorecard rules and write CQL queries based on Coralogix alerts.

See more examples in the [CQL Explorer](https://app.getcortexapp.com/admin/cql-explorer) in Cortex.

<details>

<summary>Check if Coralogix application is set</summary>

Check if entity has a registered Coralogix application in its entity descriptor. If no registration exists, we'll try to automatically detect which corresponding Coralogix application is associated with the entity.

**Definition:** `coralogix (==/!=) null: Boolean`

**Example**

You could write a rule that checks whether an entity has a Coralogix application set:

```
coralogix != null
```

</details>

<details>

<summary>Alerts</summary>

List of alerts, filterable on status

**Definition:** `coralogix.alerts(): List`

**Example**

You could write a rule that checks whether an entity has at least 3 alerts:

```
ccoralogix.alerts().length >= 3
```

You could write a rule that checks whether an entity has no alerts and status triggered:

```
coralogix.alerts(statuses = ["triggered"]).length -= 0
```

</details>

### View integration logs <a href="#still-need-help" id="still-need-help"></a>

{% hint style="info" %}
This feature is available in Cortex cloud.
{% endhint %}

While viewing an integration's settings page, select the **Logs** tab to view error logs from the last 7 days. You can filter the logs list by configuration and by operation (for example, you could filter to view errors surfaced only via Scorecards).

<div align="left" data-with-frame="true"><figure><img src="/files/x8JmoPqXZTJ7YHeFJpOA" alt="The &#x27;Logs&#x27; tab on an integration&#x27;s settings page shows error information over the past 7 days."><figcaption></figcaption></figure></div>

Click into a row to get more information, including time stamp, status code, full error, and request path.


# Custom webhook integrations

Custom webhook integrations allow you to POST data to a unique endpoint in Cortex, map the payload to existing entities, and make that data available for use in [Scorecards](/standardize/scorecards), [CQL queries](/standardize/cql), and on [entity detail pages](/ingesting-data-into-cortex/entities-overview/entities/details).

Using a custom webhook is especially helpful if:

* You have internal tools, homegrown systems, or third-party services that Cortex doesn't integrate with yet.
* You want to automate the process of sending custom metrics, events, or other data into Cortex without building and maintaining additional infrastructure.
* You want to pre-process data before it reaches Cortex, such as adding extra metadata or transforming the payload format.

This can be done without auth or an explicit [Cortex tag](/ingesting-data-into-cortex/entities-overview/entities#cortex-tag) in the URL if you do not have access to the Cortex tag or the ability to add authentication headers.

{% hint style="info" %}
You can also add custom metadata manually to an entity descriptor or programmatically via the API. Learn more in [Adding custom data](/ingesting-data-into-cortex/entities-overview/entities/custom-data).
{% endhint %}

Below the instructions, see an example demonstrating how to [send additional GitHub metadata into Cortex via webhook](#example-github-webhook).

## How to create a custom webhook integration in Cortex

### Step 1: Configure the custom integration in Cortex

1. In Cortex, navigate to **Integrations**. On the left side of the Integrations page, click [**Custom integrations**](https://app.getcortexapp.com/admin/integrations#integration-category-custom).
2. Click **+Add custom integration**.\\

   <figure><img src="/files/8BueJl5ZSioebN3Wx9a1" alt="Click +Add custom integration."><figcaption></figcaption></figure>
3. Configure the integration details:
   * **Integration name**: Enter a name for the integration.
   * **Entity tag JQ**: Enter the JQ that will be used to extract the entity's [Cortex tag](/ingesting-data-into-cortex/entities-overview/entities#cortex-tag) from the data. This tells Cortex where in the payload body we can find the Cortex tag.
     * For example, the payload shown in [Step 2](#step-2-send-data-to-the-webhook) would have `.data.codeTag` as the JQ, and `frontend-service` would be the entity's Cortex tag.
     * If the tag Cortex extracts from the payload does not match an existing Cortex tag, it will result in a 400 error and the custom metadata will not be updated. Learn about [alternate mappings below](#changing-the-mappings-for-entities).
   * **Key**: Enter the custom metadata key.
     * Data will be stored under the key for entities, similar to adding data via [entity descriptor](/ingesting-data-into-cortex/entities-overview/entities#defining-entities-via-yaml-file) or [API](/api/readme/custom-data).
     * In the [example below](#step-2-post-json-with-curl), the key is `mydata`.
4. Click **Save**.
5. Copy the provided webhook URL.

### Step 2: Send data to the webhook

Note that the entity must exist in Cortex before you send the payload.

cURL is a quick and flexible method to post to the webhook and verify that it's receiving data.

1. Save your payload as a .json file. Include the field that matches the JQ expression configured in the previous steps, so Cortex can map the data to the correct entity.\
   For example, the payload might look like this:

```json
{
  "data": {
    "codeTag": "frontend-service",
    "mydata": "4"
  }
}
```

2. In your terminal, use cURL to POST the JSON, using a command similar to the following:\
   `curl -X POST -H "Content-Type: application/json" --data <path to json file> <webhook URL>`
   * For example: `curl -X POST -H "Content-Type: application/json" --data @/tmp/payload.json https://api.getcortexapp.com/api/v1/custom-integrations/data/12345abcdef`

After sending data, the JSON payload is written to the entity's key that you configured for the custom webhook in [Step 1](#step-1-configure-the-custom-integration-in-cortex).

### **Changing the mappings for entities**

If the webhook payload does not contain a value that maps to the exact [Cortex tag](/ingesting-data-into-cortex/entities-overview/entities#cortex-tag), you can configure alternative mappings to look up when processing payloads. Use the `x-cortex-custom-integration-mappings` block in the [entity descriptor YAML](/ingesting-data-into-cortex/entities-overview/entities#defining-entities-via-yaml-file). For example:

```yaml
x-cortex-custom-integration-mappings:
  - frontend
  - brain-service
```

When processing a payload, Cortex takes the output of the **Entity tag JQ** field in Step 1 above and searches for an entity with that value as a Cortex tag. If no such entity exists, Cortex checks whether an entity has registered the value as an alternative mapping; if so, the payload is attached to that entity.

## View custom integration data in Cortex

Similar to when you [add custom metadata to an entity](/ingesting-data-into-cortex/entities-overview/entities/custom-data), custom integration data appears in the sidebar on an [entity details page](/ingesting-data-into-cortex/entities-overview/entities/details) within the **Custom data & metrics** page. It appears with an `INTEGRATION` tag next to the key name.

<figure><img src="/files/aVzQZIqyffyMMYWP3e5R" alt="The &#x22;Custom data and metrics&#x22; page in an entity&#x27;s sidebar displays data from webhook integrations."><figcaption></figcaption></figure>

## Example: GitHub webhook

In this example, we create a webhook integration to send GitHub data into Cortex.

While Cortex does offer a native integration with [GitHub](/ingesting-data-into-cortex/integrations/github), there may be scenarios where you want to send additional metadata that isn't included in the native integration.

1. [Create a custom webhook integration](#step-1-configure-the-custom-integration-in-cortex) in Cortex.
   * Enter a descriptive name so others understand the purpose of this webhook, such as "GitHub metadata."
   * In this example, we use the **Service query** `.repository.name` and the **Key** `githubTest`.
2. Copy the webhook URL generated in Cortex for this integration.
3. In GitHub, under **Settings > Webhooks**, create a webhook.
   * In the webhook's settings under **Payload URL**, paste in the webhook URL from Cortex.
   * Set the **Content type** to `application/json`.
4. Push a commit to your GitHub repository.
   * In your GitHub settings under **Webhooks**, click the **Recent Deliveries** tab to see the payload that will be sent. Because you set the JQ query to `.repository.name`, the repository name value in the payload will correspond with the Cortex tag in Cortex.\
     In the example screen shot, the repository name is "michigan":\\

     <div align="left"><figure><img src="/files/0vS3oC9itnB3gt93zSjO" alt="The repository name appears in the &#x22;Recent deliveries&#x22; tab for the webhook in GitHub." width="563"><figcaption></figcaption></figure></div>
5. Navigate to the entity in Cortex.
   * In this example, the repository name is "michigan," so we can search in Cortex to find an entity with "michigan" as its Cortex tag.
6. On the [entity's details page](/ingesting-data-into-cortex/entities-overview/entities/details), click **Custom data & metrics** from the entity's sidebar.
   * Next to the `githubTest` key, you will see the payload sent from GitHub:\\

     <figure><img src="/files/Mnrr15Y0TFbPSlzBZeCj" alt="The custom webhook data appears next to the key on the entity page."><figcaption></figcaption></figure>


# Datadog

{% hint style="info" %}
Cortex connects to many third-party vendors whose system interfaces frequently change. As a result, integration behavior or configuration steps may shift without notice. If you encounter unexpected issues, check with your system administrator or refer to the vendor's documentation for the most current information. Additionally, integration sync times vary and are subject to scheduling overrides and timing variance.
{% endhint %}

[Datadog](https://www.datadoghq.com/) is an application performance monitoring platform that provides real-time observability into entities, servers, databases, and tools, providing developers with a comprehensive understanding of their infrastructure as well as the ability to identify areas for improvement.

Cortex is uniquely equipped to augment Datadog's tools, providing greater visibility into your entities. In this guide, you'll learn how to set up the Datadog integration to pull in services and metrics for entities:

* Monitors
* SLOs
* Dependencies

{% hint style="info" %}
Cortex syncs Datadog monitor and SLO data on a background schedule, so values in Cortex may lag live Datadog by up to 30 minutes.
{% endhint %}

## How to configure Datadog with Cortex

### Prerequisites

Before getting started, make sure you have created the following:

* [Datadog application key](https://docs.datadoghq.com/account_management/api-app-keys/#application-keys)
  * You can create this in Datadog under **Organizational Settings > Applications Key**.
  * Include the following scopes:
    * `monitors_read`
    * `apm_api_catalog_read`
    * `dashboards_read`
    * `metrics_read`
    * `timeseries_query`
    * `apm_service_catalog_read`
    * `slos_read`
    * `apm_read`
* [Datadog API key](https://docs.datadoghq.com/account_management/api-app-keys/#api-keys)
  * You can create this in Datadog under **Organizational Settings > API Key**.

### Configure the integration in Cortex

1. In Cortex, navigate to the [Datadog settings page](https://app.getcortexapp.com/admin/integrations/datadog).
   * Click **Integrations** from the main nav. Search for and select Datadog.
2. Click **Add configuration**.
3. Configure the Datadog integration form:
   * **Account alias**: Enter a name that Cortex will associate this configuration with.
   * **App key**: Enter the application key you generated in Datadog.
     * This key appears under the **Key** column in Datadog while viewing your list of Application Keys.\\

       <figure><img src="/files/KgS974hwMM9TivrrKvkj" alt=""><figcaption></figcaption></figure>
   * **API key**: Enter the API key you generated in Datadog.
   * **Region**: Select your [Datadog region](https://docs.datadoghq.com/getting_started/site/) from the dropdown.
   * **Custom subdomain**: Enter the custom subdomain for your Datadog instance.
     * This field only takes the subdomain, not the entire URL. For example, this field would take `cortex-docs` from `https://cortex-docs.datadoghq.com`.
   * **Environments**: Optionally, enter environment tags for Datadog entities.
     * If you set an environment tag here, make sure to set the [`env` dropdown in Datadog](https://docs.datadoghq.com/service_catalog/navigating/#performance-view) to match.
4. Click **Save**.

After saving your configuration, you are redirected to the Datadog integration settings page in Cortex. In the upper right corner of the page, click **Test configuration** to ensure Datadog was configured properly.

#### **Configure the integration for multiple Datadog accounts**[**​**](https://docs.cortex.io/docs/reference/integrations/datadog#configure-the-integration-for-multiple-propsintegration-accounts)

The Datadog integration has multi-account support. You can add a configuration for each additional by repeating the process above.

Each configuration requires an alias, which Cortex uses to correlate the designated with registrations for various entities. Registrations can also use a default configuration without a listed alias. You can edit aliases and default configurations from the Datadog page in your Cortex settings. Select the edit icon next to a given configuration and toggle **Set as default** on. If you only have one configuration, it will automatically be set as the default.How to connect Cortex entities to Datadog

## How to connect Cortex entities to Datadog

### Tag discovery

By default, Cortex will use the [Cortex tag](/ingesting-data-into-cortex/entities-overview/entities#cortex-tag) (e.g. `my-entity`) as the "best guess" for Datadog tag. For example, if your Cortex tag is `my-entity`, then the corresponding tag in Datadog should also be `my-entity`.

If your Datadog tags don’t cleanly match the Cortex tag, you can override this in the Cortex entity descriptor.

### Import entities from Datadog

See the [Create services documentation](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/add-services#creating-services) for instructions on importing entities.

### Editing the entity descriptor

You can use service tags to connect Datadog services to Cortex entities.

```yaml
x-cortex-apm:
  datadog:
    serviceTags:
      - tag: entity
        value: brain
        alias: my-default-alias
      - tag: entity
        value: cerebrum
        alias: my-other-alias
```

| Field   | Description                                                                                         | Required |
| ------- | --------------------------------------------------------------------------------------------------- | -------- |
| `tag`   | Tag for the project in Datadog                                                                      | **✓**    |
| `value` | Value for the project; Cortex will find monitors and SLOs by querying `tag:value OR tag:value2 ...` | **✓**    |
| `alias` | Alias for the configuration in Cortex (only needed if you have opted into multi-account support)    |          |

These tags are used to "discover" your monitors and SLOs. Cortex will find monitors and SLOs by querying `tag:value OR tag:value2 ...`

If you want to hard code and/or override discovery, you can define a monitor or SLOs block in the entity descriptor, as described below.

#### **Monitors and SLOs**

Adding monitors let you see information about their current status directly from a catalog - via the Monitors column - and under the `Operations` section of an entity page. You can find your monitors from Datadog's [Manage Monitors page](https://app.datadoghq.com/monitors/manage).

The ID of a monitor is found in the URL when you click on a monitor in your Datadog dashboard i.e., `https://app.datadoghq.com/monitors/****`.

```yaml
info:
  x-cortex-apm:
    datadog: 
      monitors:
        - id: 12345
          alias: my-default-alias
        - id: 67890
          alias: my-other-alias
```

Like monitors, Datadog SLOs can be found in the `Operations` section of an entity page. You can find the SLOs for your instance on Datadog's [SLO status page](https://app.datadoghq.com/slo).

The ID for the SLO can be found in the URL when you click on an SLO in the Datadog dashboard. For example, `https://app.datadoghq.com/slo?slo_id=****&timeframe=7d&tab=status_and_history`.

```yaml
info:
  x-cortex-slos:
    datadog:
      - id: 0b73859a3e2504bf09ad23a161702654
        alias: my-default-alias
      - id: 228499184a9efe34d4e4e9df838c7fa1
        alias: my-other-alias
```

Monitors and SLOs have the same field definitions.

| Field   | Description                                                                                      | Required |
| ------- | ------------------------------------------------------------------------------------------------ | :------: |
| `id`    | Datadog ID for the monitor or SLO                                                                |   **✓**  |
| `alias` | Alias for the configuration in Cortex (only needed if you have opted into multi-account support) |          |

### Dependency mapping

Cortex automatically syncs dependencies from Datadog's [Service Map](https://docs.datadoghq.com/tracing/services/services_map/), using the entity identifier (`x-cortex-tag`) to map entities found in the Service Map.

The relationships Cortex discovers through the integration will feed directly into the [Relationships graph](https://app.getcortexapp.com/admin/graph), so you can easily visualize the connections between your entities.

If you have two entities - for example, `entity-one` and `entity-two` - that have a dependency edge in Datadog's Service Map, both entities should exist in Cortex with the same identifiers ([Cortex tag](/ingesting-data-into-cortex/entities-overview/entities#cortex-tag)).

You can override this by [defining Cortex tags](#editing-the-entity-descriptor) where `tag` = `entity` and `value` = `entity name in Datadog Service Map`.

{% hint style="warning" %}
If the Cortex tag does not exactly match the entity identifier in Datadog, the dependencies will not automatically sync. You can override automatic discovery by defining values in the entity descriptor.
{% endhint %}

You can connect an APM service for dependency mapping in the entity descriptor:

```yaml
x-cortex-apm:
  datadog:
    serviceName: cortex-gateway.gateway
```

## Using the Datadog integration

### View Datadog monitors and SLOs on entity pages

With the Datadog integration, you'll be able to find monitors and SLOs on an entity's home page. High-level information about monitors and SLOs appears in the **Overview** tab.

Click **Monitoring** in the entity's sidebar to see more detailed data about both monitors and SLOS. Both sections display tags for Pass, Fail, Warning, and No Data for each monitor or SLO.

* The **SLOs** column shows each SLO, its target(s), the current value for that entity, its status. and the period of time the SLO is being calculated for. For example, if the time listed is "7 days ago," then the SLO is looking at the time range starting 7 days ago to now\..
* The **Monitors** column shows the title for each monitor, its query (if available), and its status.

Clicking any block with a nonzero value will open a modal with more detailed information. The monitor modals will list all monitors with the applicable status. The SLO modals will also display targets for each SLO that is passing or failing.

### Scorecards and CQL

With the Datadog integration, you can create Scorecard rules and write CQL queries based on Datadog metrics, monitors, and SLOS.

See more examples in the [CQL Explorer](https://app.getcortexapp.com/admin/cql-explorer) in Cortex.

You can read more about Datadog's [metrics](https://docs.datadoghq.com/metrics/types/) and [custom metrics](https://docs.datadoghq.com/metrics/custom_metrics/) in their docs.

<details>

<summary>Metrics</summary>

[Timeseries data](https://docs.datadoghq.com/api/latest/metrics/#query-timeseries-data-across-multiple-products) from Datadog.

* Metric
* Timestamp

**Definition:** `datadog.metrics(query: Text, lookback: Duration, alias: Text | Null)`

**Example**

You can use the `datadog.metrics()` expression to evaluate the health of your entities in a Scorecard:

```
datadog.metrics(query="system.cpu.usage{service:" + datadog.serviceNames().join(" OR service:") + "}",lookback=duration("P2D")).averageBy((point) => point.metricValue) < 0.10
```

This rule makes sure that a given entity's average CPU usage is less than 10% over the last two days.

</details>

<details>

<summary>Monitors</summary>

Monitors associated with a given entity via ID or tags. You can use these data to check whether an entity has monitors associated with it, or whether an entity has the right types of monitors.

* Created at
* Creator email
* Creator name
* Name
* Overall state
* Query
* Tags
* URL

**Definition:** `datadog.monitors()`

**Example**

For a Scorecard focused on operational maturity, this expression can be used to make sure an entity has at least one Datadog monitor set up:

```
datadog.monitors().length >= 1
```

</details>

<details>

<summary>SLOs</summary>

SLOs associated with a given entity via ID or tags. You can use these data to check whether an entity has SLOs associated with it and if those SLOs are passing.

* History
* ID
* Name
* Operation
* Remaining budget
* SLI value
  * Datum
  * Timeseries
* SLO target
* Source
* Thresholds
  * Name
  * Threshold

**Definition:** `slos()`

**Examples**

For a Scorecard focused on operational maturity, this expression can be used to make sure an entity has associated SLOs in Datadog:

```
slos().length > 0
```

This rule checks that there is at least one SLO is set up. While this rule makes sense in a Scorecard's first level, a rule checking the status of the SLO would make sense in a higher level:

```
slos().all((slo) => slo.passing)
```

Entities will pass this rule if all SLOs associated with it have "passing" status.

</details>

### Discovery audit

Cortex will pull recent changes from your Datadog environment into the [discovered entities list](/ingesting-data-into-cortex/entities-overview/entities/discovery-audit). Here, you can find new entities in Datadog that have not been imported into the catalog - these will have the tag **New APM Resource** - as well as entities in the catalog that no longer exist in Datadog - these will have the tag **APM Resource Not Detected**.

### View integration logs <a href="#still-need-help" id="still-need-help"></a>

{% hint style="info" %}
This feature is available in Cortex cloud.
{% endhint %}

While viewing an integration's settings page, select the **Logs** tab to view error logs from the last 7 days. You can filter the logs list by configuration and by operation (for example, you could filter to view errors surfaced only via Scorecards).

<div align="left" data-with-frame="true"><figure><img src="/files/x8JmoPqXZTJ7YHeFJpOA" alt="The &#x27;Logs&#x27; tab on an integration&#x27;s settings page shows error information over the past 7 days."><figcaption></figcaption></figure></div>

Click into a row to get more information, including time stamp, status code, full error, and request path.

## Background sync

**Monitors and SLOs** - Cortex syncs Datadog monitor and SLO data on a background schedule, so values in Cortex may lag live Datadog by up to 30 minutes.

**Dependencies** - The dependency sync runs automatically each day at 12 a.m. UTC, and can be run manually via the [**Sync dependencies** button](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/dependencies#sync-dependencies) in the [relationship graph](/ingesting-data-into-cortex/entities-overview/entities/relationship-graph).

## FAQs and troubleshooting

**Can I set a Scorecard rule to monitor Datadog monitors/SLOs based on tags?**

Yes, you can [specify key-value pairs](#entity-descriptor) that allow Cortex to discover your SLOs and monitors, and use these tags in Scorecard rules.

**How does Datadog work with other dependency sources?**

When leveraging multiple dependency sources such as Datadog and a catalog entity's YAML, all the sources would be merged together and Cortex will de-duplicate the dependencies.

For example, if an entity YAML indicates `X → Y` and Datadog indicates `X → Y` and `X → Z`, the entity will display two edges presented as `X → Y` and `X → Z`.


# Dynatrace

{% hint style="info" %}
Cortex connects to many third-party vendors whose system interfaces frequently change. As a result, integration behavior or configuration steps may shift without notice. If you encounter unexpected issues, check with your system administrator or refer to the vendor's documentation for the most current information. Additionally, integration sync times vary and are subject to scheduling overrides and timing variance.
{% endhint %}

### Overview

[Dynatrace](https://www.dynatrace.com/) is a monitoring and observability platform. Integrate Dynatrace with Cortex to get insights into application performance, service discovery, SLOs, and dependencies.

## How to configure Dynatrace with Cortex

### Prerequisite

Before getting started, generate an [access token in Dynatrace](https://www.dynatrace.com/support/help/dynatrace-api/basics/dynatrace-api-authentication) with the scopes `Read entities` and `Read SLO`.

### Configure the integration in Cortex

1. In Cortex, navigate to the [Dynatrace settings page](https://app.getcortexapp.com/admin/integrations/dynatrace).
   * Click **Integrations** from the main nav. Search for and select Dynatrace.
2. Click **Add configuration**.
3. Configure the Dynatrace integration form:
   * **Domain**: Enter your [Dynatrace domain](https://www.dynatrace.com/support/help/dynatrace-api/environment-api/entity-v2/get-entities-list) necessary to access your environment, depending on whether you use managed, SaaS, or the Environment ActiveGate version.
   * \**API token*: Enter the access token you generated in Dynatrace.
4. Click **Save**.

If you’ve set everything up correctly, you’ll see the option to **Remove Integration** in settings.

You can also use the **Test configuration** button to confirm that the configuration was successful. If your configuration is valid, you’ll see a banner that says “Configuration is valid. If you see issues, please see documentation or reach out to Cortex support.”

## How to connect Cortex entities to Dynatrace

### Import entities from Dynatrace

See the [Create services documentation](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/add-services#creating-services) for instructions on importing entities.

### Editing the entity Entity descriptor

**Entity ID**

Entities with a type of `"SERVICE"` will be discovered and surfaced. When using the Dynatrace portal, service IDs can be found in the URL of a selected service under the id query param. For example, `https://.live.dynatrace.com/#newservices/serviceOverview;id=`

```yaml
x-cortex-apm:
  dynatrace:
    entityIds:
      - mock-service-id-1
      - mock-service-id-2
```

**Entity name**

You can also match entities based on matching [display names](https://www.dynatrace.com/support/help/dynatrace-api/environment-api/entity-v2/get-entities-list#response-body-objects) with a regular expression, like:

```yaml
x-cortex-apm:
  dynatrace:
    entityNameMatchers:
      - "foo.*"
```

#### Linking SLOs in Cortex

Dynatrace supports service-level objective (SLO) monitoring. You can link these SLOs to your Dynatrace entity in Cortex:

1. In Dynatrace, navigate to the Service-Level Objectives app.
   * On the left sidebar of Dynatrace, click **Search**, then type in `slo` to find the app.
2. On the SLOs page, see the list of SLOs. On the right side of an SLO, click **^** to expand the Details.\
   ![The details button is on the right side of an SLO](/files/16oS9WHFjjgR3g6MjQ2Y)
3. In your browser's URL bar, locate the ID in the URL. Copy the ID and store it in a secure location, as you will need this value in the next steps.
   * The ID is displayed in the URL following `sloexp=`. For example, `https://.apps.dynatrace.com/ui/.../sloexp=&slovis=` ![The SLO ID is in the URL](/files/OrsTEqiiiTcxSDYQXs3M)
   * On the SLOs page, expand the details for each SLO to display the SLO ID in the URL.
4. Open your Cortex home page, then navigate to the service you are configuring.
5. In the upper right corner of the service page, click **Switch to YAML**.
6. Paste in the following text, making sure to replace `slo-id-1` and `slo-id-2` with the SLO IDs you obtained from the Dynatrace URL in the previous steps:

```yaml
x-cortex-slos:
  dynatrace:
    - id: slo-id-1
    - id: slo-id-2
```

7. At the bottom of the page, click **Save**.

After saving, navigate back to your service details page to view the SLO status in the service's Overview tab.

For information on working with SLOs in Dynatrace, see [Dynatrace's documentation](https://docs.dynatrace.com/docs/platform-modules/automations/service-level-objectives/configure-and-monitor-slo).

#### Dependencies

Cortex automatically syncs [dependencies](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/dependencies) from Dynatrace using attributes inherent to each entity.

#### Discovery audit

Cortex will pull recent changes from your Dynatrace instance into the [discovered entities list](/ingesting-data-into-cortex/entities-overview/entities/discovery-audit). Here, you can find new entities in Dynatrace that have not been imported into the catalog - these will have the tag **New APM resource** - as well as entities in the catalog that no longer exist in Dynatrace - these will have the tag **APM resource not detected**.

## Using the Dynatrace integration

#### Entity pages

With the Dynatrace integration, you'll see SLOs on an entity's home page. High-level information about SLOs appears in the **Overview** tab.

Click **Monitoring** in the entity's sidebar to see more detailed data: the SLO name, its target, the current value for that entity, and the period of time the SLO is being calculated for. For example, if the time listed is "7 days ago," then the SLO is looking at the time range starting 7 days ago to now.

#### Relationship graphs

[Dependencies](#dependencies) detected from Dynatrace will appear in [Relationship graphs](https://app.getcortexapp.com/admin/graph).

### Scorecards and CQL

With the Dynatrace integration, you can create Scorecard rules and write CQL queries based on Dynatrace SLOs.

See more examples in the [CQL Explorer](https://app.getcortexapp.com/admin/cql-explorer) in Cortex.

<details>

<summary>SLOs</summary>

SLOs associated with a given entity via ID or tags. You can use these data to check whether an entity has SLOs associated with it and if those SLOs are passing.

* History
* ID
* Name
* Operation
* Remaining budget
* SLI value
  * Datum
  * Timeseries
* SLO target
* Source
* Thresholds
  * Name
  * Threshold

**Definition:** `slos()`

**Examples**

For a Scorecard focused on operational maturity, this expression can be used to make sure an entity has associated SLOs in Dynatrace:

```
slos().length > 0
```

This rule checks that there is at least one SLO is set up. While this rule makes sense in a Scorecard's first level, a rule checking the status of the SLO would make sense in a higher level:

```
slos().all((slo) => slo.passing)
```

Entities will pass this rule if all SLOs associated with it have "passing" status.

</details>

### View integration logs <a href="#still-need-help" id="still-need-help"></a>

{% hint style="info" %}
This feature is available in Cortex cloud.
{% endhint %}

While viewing an integration's settings page, select the **Logs** tab to view error logs from the last 7 days. You can filter the logs list by configuration and by operation (for example, you could filter to view errors surfaced only via Scorecards).

<div align="left" data-with-frame="true"><figure><img src="/files/x8JmoPqXZTJ7YHeFJpOA" alt="The &#x27;Logs&#x27; tab on an integration&#x27;s settings page shows error information over the past 7 days."><figcaption></figcaption></figure></div>

Click into a row to get more information, including time stamp, status code, full error, and request path.

## Background sync

Cortex conducts a background sync of Dynatrace entities at 7 a.m. UTC and a dependency sync every day at 12 a.m. UTC. You can [manually sync dependencies](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/dependencies#sync-dependencies) via the Relationship Graph.


# Entra ID

{% hint style="info" %}
Cortex connects to many third-party vendors whose system interfaces frequently change. As a result, integration behavior or configuration steps may shift without notice. If you encounter unexpected issues, check with your system administrator or refer to the vendor's documentation for the most current information. Additionally, integration sync times vary and are subject to scheduling overrides and timing variance.
{% endhint %}

[Microsoft Entra ID](https://www.microsoft.com/en-us/security/business/identity-access/microsoft-entra-id), formerly known as Azure Active Directory, is an identity service that provides SSO and authentication.

Integrating Cortex with Entra ID allows you to:

* Automatically discover and track Entra ID teams and team memberships
* Track ownership of entities
* Create [Scorecards](#scorecards-and-cql) that track progress and drive alignment on projects involving your Entra ID teams

{% hint style="info" %}
For information on configuring Entra ID SSO for logging in to Cortex, see the [Microsoft Entra ID SSO documentation](/configure/settings/managing-users/configuring-sso/entraid).
{% endhint %}

## How to configure Entra ID with Cortex

### Step 1: Register and configure a new Active Directory application

1. Follow Microsoft's documentation to [register a new single tenant Entra ID application](https://learn.microsoft.com/en-us/entra/identity-platform/quickstart-register-app?tabs=certificate#register-an-application).
2. In your Entra ID admin center, navigate to your new application, and then to API Permissions. Add the following permissions:
   * Microsoft APIs > Microsoft Graph > Application permissions > User > `User.Read.All`
   * Microsoft APIs > Microsoft Graph > Application permissions > Group > `Group.Read.All`
3. Click **Grant Admin Consent** to grant permissions for all accounts in the directory.
4. Navigate to **Certificates & secrets** and click **New client secret**.
   * Note that you will need to rotate the secret before the expiration date you set for it.
5. Navigate to the application's Overview page and copy the client ID. You will need the client ID and secret in the next steps.

### Step 2: Configure the integration in Cortex

1. In Cortex, navigate to the [Entra ID settings page](https://app.getcortexapp.com/admin/integrations/microsoft-entra-id).
   * Click **Integrations** from the main nav. Search for and select **Entra ID**.
2. Click **Add configuration**.
3. Configure the integration form:
   * **Tenant ID**: Enter your Entra ID [tenant ID](https://learn.microsoft.com/en-us/entra/fundamentals/how-to-find-tenant#find-tenant-id-through-the-azure-portal).
   * **Client ID** and **Client secret**: Enter the client ID and secret you generated in the previous steps.
4. Click **Save**.
   * You will be redirected to the Azure Active Directory settings page in Cortex, where you can optionally set a group filter to limit which groups are pulled in from Entra ID.

## How to connect Cortex entities to Entra ID

### Import entities from Entra ID

See the [Create services documentation](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/add-services#creating-services) for instructions on importing entities.

### Editing the entity descriptor

```yaml
x-cortex-owners:
  - type: group
    name: Engineering # group name in Entra ID
    provider: ACTIVE_DIRECTORY
```

The group name is case-sensitive and should be exactly the same as in Entra ID.

## Using the Entra ID integration

### Teams page

Under **Catalogs > Teams**, you will see teams and team members pulled in from Entra ID.

### Entity pages

If you have ownership of entities set up, then Azure AD teams and users will be listed in the **Owners** page for an entity.

### Scorecards and CQL

With the Entra ID integration, you can create Scorecard rules and write CQL queries based on Entra ID teams.

See more examples in the [CQL Explorer](https://app.getcortexapp.com/admin/cql-explorer) in Cortex.

<details>

<summary>All ownership details</summary>

A special built-in type that supports a null check or a count check, used to enforce ownership of entities.

**Definition:** `ownership: Ownership | Null`

**Example**

An initial level in a security Scorecard might include a rule to ensure an entity has at least one team as an owner:

```
ownership.teams().length > 0
```

</details>

<details>

<summary>All owner details</summary>

List of owners, including team members and individual users, for each entity

**Definition:** `ownership.allOwners()`

**Example**

The Scorecard might include a rule to ensure that entity owners all have an email set:

```
ownership.allOwners().all((member) => member.email != null)
```

</details>

### View integration logs <a href="#still-need-help" id="still-need-help"></a>

{% hint style="info" %}
This feature is available in Cortex cloud.
{% endhint %}

While viewing an integration's settings page, select the **Logs** tab to view error logs from the last 7 days. You can filter the logs list by configuration and by operation (for example, you could filter to view errors surfaced only via Scorecards).

<div align="left" data-with-frame="true"><figure><img src="/files/x8JmoPqXZTJ7YHeFJpOA" alt="The &#x27;Logs&#x27; tab on an integration&#x27;s settings page shows error information over the past 7 days."><figcaption></figcaption></figure></div>

Click into a row to get more information, including time stamp, status code, full error, and request path.

## Background sync

Cortex conducts an ownership sync every day at 6 a.m. UTC.

## FAQ and Troubleshooting

**Why were all my Entra ID users unexpectedly deleted after rotating my client secret?**

Updating your configuration can cause a temporary deletion of users. When you delete the old secret from your Azure AD configuration in Cortex, a sync is triggered to delete the users. The addition of the new secret to your configuration will trigger a sync to add the users. There may be a delay before seeing the users re-added.

## Still need help?[​](https://docs.cortex.io/docs/reference/integrations/aws#still-need-help) <a href="#still-need-help" id="still-need-help"></a>

The following options are available to get assistance from the Cortex Customer Engineering team:

* **Email**: <help@cortex.io>, or open a support ticket in the in app Resource Center
* **Slack**: Users with a connected Slack channel will have a workflow added to their account. From here, you can either @CortexTechnicalSupport or add a `:ticket:` reaction to a question in Slack, and the team will respond directly.

Don’t have a Slack channel? Talk with your Customer Success Manager.


# FireHydrant

{% hint style="info" %}
Cortex connects to many third-party vendors whose system interfaces frequently change. As a result, integration behavior or configuration steps may shift without notice. If you encounter unexpected issues, check with your system administrator or refer to the vendor's documentation for the most current information. Additionally, integration sync times vary and are subject to scheduling overrides and timing variance.
{% endhint %}

[FireHydrant](https://firehydrant.com/) is an incident management platform that emphasizes reliability and consistency across the entire incident response lifecycle.

Integrating FireHydrant with Cortex allows you to:

* [View incidents on entity pages](#viewing-firehydrant-incidents-on-an-entity) in Cortex, giving you insight into incidents to act on them quickly
* [Trigger new incidents](#trigger-an-incident) directly from Cortex
* Create [Scorecards](#scorecards-and-cql) to set standards around incident management and production readiness

## How to integrate FireHydrant with Cortex

### Prerequisites

Before getting started:

* Create a [FireHydrant API key](https://app.firehydrant.io/settings/api_keys).

### Configure the integration in Cortex

1. In Cortex, navigate to the [FireHydrant settings page](https://app.getcortexapp.com/admin/integrations/firehydrant):
   * Click **Integrations** from the main nav. Search for and select **FireHydrant**.
2. Click **Add configuration**.
3. Configure the integration:
   * **API key**: Enter the API key you created in FireHydrant.
4. Click **Save**.

## How to connect Cortex entities to FireHyrant projects

### Editing the entity descriptor

You can define FireHydrant services in an [entity's YAML file](/ingesting-data-into-cortex/entities-overview/entities#defining-entities-via-yaml-file).

For a given entity, define FireHydrant services by ID or slug. Each of these has the same field definitions.

| Field            | Description                         | Required |
| ---------------- | ----------------------------------- | :------: |
| `identifier`     | Service ID or slug                  |   **✓**  |
| `identifierType` | Type of identifier (`ID` or `SLUG`) |   **✓**  |

```yaml
x-cortex-firehydrant:
  services:
    - identifier: ASDF1234
      identifierType: ID
```

You can find the service ID value in FireHydrant under **FireHydrant > Catalog > Services**. The URL for the service will also contain the ID (e.g., `https://app.firehydrant.io/catalog/services/{ID}/incidents`).

If you prefer to use the service slug in the registration instead, you can find it on the right-hand side of the service page in FireHydrant.

```yaml
x-cortex-firehydrant:
  services:
    - identifier: service-slug
      identifierType: SLUG
```

## Using the FireHydrant integration

### Viewing FireHydrant incidents on an entity

When active incidents are detected in FireHydrant, Cortex will display incident information on an [entity's details page](/ingesting-data-into-cortex/entities-overview/entities/details).

Click **On-call & incidents** in the entity's sidebar to see all detected incidents.

Each issue will be listed with its title and description (when available). Cortex will also display the status for an issue as a badge next to its name:

* `Acknowledged`
* `Closed`
* `Detected`
* `Identified`
* `Investigating`
* `Mitigated`
* `Postmortem completed`
* `Postmortem started`
* `Resolved`
* `Started`

The issue's severity will also appear in a badge (e.g. `SEV0`, `SEV1`, `SEV2`).

### **Trigger an incident**

While viewing an entity in Cortex, you can trigger an incident in FireHydrant:

1. In Cortex, navigate to an entity. On the left side of an entity details page, click **On-call & incidents.**
2. In the upper right side of the entity's "On-call" page, click **Trigger incident**.
3. Configure the incident modal:
   * **Summary**: Enter a title for the incident.
   * **Description**: Enter a description of the incident.
   * **Severity**: Select a severity level.
   * **Condition:** Nature of the incident - `Unavailable`, `Partially Unavailable`, `Degraded`, `Bug`, or `Operational`.
4. At the bottom of the modal, click **Trigger incident**.
   * A confirmation screen will appear. In the confirmation, click the link to view the incident in FireHydrant.

### Scorecards and CQL

With the FireHydrant integration, you can create Scorecard rules and write CQL queries based on FireHydrant incidents.

See more examples in the [CQL Explorer](https://app.getcortexapp.com/admin/cql-explorer) in Cortex.

<details>

<summary>Check if FireHydrant service is set</summary>

Check if entity has a registered FireHydrant service in its entity descriptor. If no registration exists, we'll try to automatically detect which corresponding FireHydrant service is associated with the entity.

**Definition:** `firehydrant (==/!=) null`

**Example**

For a Scorecard focused an production readiness, you can use this expression to make sure a FireHydrant service - and thus incident response - is defined for entities:

```
firehydrant != null
```

This is also a good way to make sure over time that FireHydrant is set up properly and reporting frequently.

</details>

<details>

<summary>Incidents</summary>

List of incidents, filterable on severity and status.

* Created at
* Description
* Impact condition name
* Name
* Severity
* Status

**Definition:** `firehydrant.incidents()`

**Examples**

For a Scorecard focused on service maturity or quality, you can use this expression to make sure there are no detected or identified FireHydrant incidents with a severity rating of 1 for a given entity:

```
firehydrant.incidents(severity = ["SEV1"], statuses = ["Detected", "Identified"]).length == 0
```

You can also tier severity-based rules to indicate progress over time. While the above rule might make sense in the first or second level, a higher-severity rule might make sense in a higher level:

```
firehydrant.incidents(severity = ["SEV3"], statuses = ["Detected", "Identified"]).length == 0
```

</details>

### View integration logs <a href="#still-need-help" id="still-need-help"></a>

{% hint style="info" %}
This feature is available in Cortex cloud.
{% endhint %}

While viewing an integration's settings page, select the **Logs** tab to view error logs from the last 7 days. You can filter the logs list by configuration and by operation (for example, you could filter to view errors surfaced only via Scorecards).

<div align="left" data-with-frame="true"><figure><img src="/files/x8JmoPqXZTJ7YHeFJpOA" alt="The &#x27;Logs&#x27; tab on an integration&#x27;s settings page shows error information over the past 7 days."><figcaption></figcaption></figure></div>

Click into a row to get more information, including time stamp, status code, full error, and request path.

## Still need help?[​](https://docs.cortex.io/docs/reference/integrations/aws#still-need-help) <a href="#still-need-help" id="still-need-help"></a>

The following options are available to get assistance from the Cortex Customer Engineering team:

* **Email**: <help@cortex.io>, or open a support ticket in the in app Resource Center
* **Slack**: Users with a connected Slack channel will have a workflow added to their account. From here, you can either @CortexTechnicalSupport or add a `:ticket:` reaction to a question in Slack, and the team will respond directly.

Don’t have a Slack channel? Talk with your Customer Success Manager.


# GitHub

{% hint style="info" %}
Cortex connects to many third-party vendors whose system interfaces frequently change. As a result, integration behavior or configuration steps may shift without notice. If you encounter unexpected issues, check with your system administrator or refer to the vendor's documentation for the most current information. Additionally, integration sync times vary and are subject to scheduling overrides and timing variance.
{% endhint %}

## Why use the integration for GitHub

GitHub is a Git-based source code management platform that helps teams share code, track changes over time, and collaborate on projects across an organization.

Integrating GitHub with Cortex allows you to:

* Automatically discover GitHub repositories and track ownership of the entities they represent in Cortex
* Manage your Cortex workspace through a GitOps workflow, using GitHub as the source of truth for entity definitions
* View repository context directly on an entity's details page, including the associated repo, recent commits and releases in the event timeline, the most-used language, and top contributors with their contribution counts
  * In an entity's **Code & Security** section, surface vulnerabilities from [GitHub Advanced Security](https://docs.github.com/en/get-started/learning-about-github/about-github-advanced-security), including code scanning, Dependabot alerts, CodeQL, and secret scanning
* Track pull requests and work items from the [engineering homepage](#engineering-homepage) to keep delivery work visible alongside the rest of your catalog
* Use GitHub metrics in [Eng Intelligence](/improve/eng-intelligence) to understand service health, incident response patterns, and other key engineering signals
* Create [Scorecards](#scorecards-and-cql) that drive alignment and measure progress on initiatives involving your repositories

You can also optionally integrate GitHub Copilot with Cortex to:

* Track Copilot adoption and measure its impact on engineering productivity within Eng Intelligence

{% hint style="info" %}
**GitHub Copilot integration**

If you installed the GitHub app prior to October 14, 2025, you must accept new permissions in order to access Copilot metrics in Cortex.

In your email, locate the message with subject line "\[GitHub] Cortex App is requesting updated permissions" from `noreply@github.com` and click the link to review and accept the change. As a security best practice, always verify that the email was sent from a trusted domain. In GitHub, click **Accept new permissions**.

Alternately, you can remove your GitHub integration in Cortex and re-configure it. The GitHub app is preconfigured to include the permissions necessary for the Copilot integration.
{% endhint %}

## Configuring GitHub

### Prerequisites

If you connect Cortex via a [custom GitHub app](#custom-app), it must be configured with a [fine-grained personal access](https://docs.github.com/en/rest/authentication/permissions-required-for-fine-grained-personal-access-tokens) token containing the minimum permissions listed below. Note that the [Cortex GitHub app](#cortex-github-app) is preconfigured with these permissions.

#### Repository permissions

<table><thead><tr><th width="204.0703125">Permission</th><th width="181.1875">Requirement</th><th>Purpose in Cortex</th></tr></thead><tbody><tr><td><strong>Actions</strong></td><td><code>Read &#x26; write</code></td><td><ul><li>Read workflow run information for Git-based CQL rules</li><li>Artifact information for actions</li></ul></td></tr><tr><td><strong>Administration</strong></td><td><code>Read &#x26; write</code></td><td>Create repositories</td></tr><tr><td><strong>Checks</strong></td><td><code>Read &#x26; write</code></td><td>Create and update check runs for linting and validation workflows, such as the <code>cortex.yaml</code> linter on pull requests</td></tr><tr><td><strong>Code scanning alerts</strong></td><td><code>Read-only</code></td><td>Get vulnerability information for Git-based CQL rules</td></tr><tr><td><strong>Commit statuses</strong></td><td><code>Read &#x26; write</code></td><td><ul><li>Read commits for an entity's Git metadata</li><li>Read commits for Git-based CQL rules</li><li>Show pending status messages on the OpenAPI incompatibility check</li></ul></td></tr><tr><td><strong>Contents</strong></td><td><code>Read &#x26; write</code></td><td><ul><li>Read <code>cortex.yaml</code>, <code>cortex-properties.yaml</code>, and package/OpenAPI files</li><li>Read Git rules</li><li>Create file contents</li></ul></td></tr><tr><td><strong>Custom properties</strong></td><td><code>Read &#x26; write</code></td><td>Used in <a href="/pages/E4BndAJAkJ3sjXz3SAer">Workflows</a></td></tr><tr><td><strong>Dependabot alerts</strong></td><td><code>Read-only</code></td><td>Read vulnerability information for Git CQL rules (only relevant if using Dependabot)</td></tr><tr><td><strong>Deployments</strong></td><td><code>Read &#x26; write</code></td><td>Used in <a href="/pages/E4BndAJAkJ3sjXz3SAer">Workflows</a></td></tr><tr><td><strong>Issues</strong></td><td><code>Read &#x26; write</code></td><td><ul><li>Read associated issues with repositories for populating entity Git integration and for Git CQL rules</li><li>Create new issues based on <a href="/pages/tdFcgLBakpb4SUx5Lotc">Initiatives</a></li></ul></td></tr><tr><td><strong>Metadata</strong></td><td><code>Read-only</code></td><td>Read associated data with repositories for populating entity Git integration and for Git CQL rules</td></tr><tr><td><strong>Pull requests</strong></td><td><code>Read &#x26; write</code></td><td><ul><li>Read pull request data for Git CQL rules and developer homepage "My PRs" tab</li><li>Comment if there are breaking OpenAPI changes on a PR</li></ul></td></tr><tr><td><strong>Secret scanning alerts</strong></td><td><code>Read-only</code></td><td>Read vulnerability information for secret scanning</td></tr><tr><td><strong>Secrets</strong></td><td><code>Read &#x26; write</code></td><td>Optionally write repo secrets after creating new repo</td></tr><tr><td><strong>Single file</strong></td><td><code>Read &#x26; write</code> (path to cortex.yaml)</td><td><ul><li>Read <code>cortex.yaml</code> files</li><li>Create <code>cortex.yaml</code> files</li></ul></td></tr><tr><td><strong>Workflows</strong></td><td><code>Read &#x26; write</code></td><td>Write in GitHub actions files</td></tr></tbody></table>

#### Organization-level permissions

<table><thead><tr><th width="215.28515625">Permission</th><th width="173.73828125">Requirement</th><th>Purpose in Cortex</th></tr></thead><tbody><tr><td><strong>Administration</strong></td><td><code>Read-only</code></td><td><ul><li>Create repositories</li><li>Pull in Copilot data for <a href="/pages/nZOyOBWYHpwwuH9q8HVF">Eng Intelligence</a></li></ul></td></tr><tr><td><strong>Members</strong></td><td><code>Read &#x26; write</code></td><td><ul><li>Read membership information for ownership and team composition</li><li>Write permission used in <a href="/pages/E4BndAJAkJ3sjXz3SAer">Workflows</a></li></ul></td></tr><tr><td><strong>GitHub copilot business</strong></td><td><code>Read-only</code></td><td>Read copilot-related metrics for AI Impact Dashboard</td></tr></tbody></table>

#### Enabling PR webhooks (optional but recommended)

Cortex ingests pull request (PR) data via the GitHub API. Subscribing to GitHub's PR webhooks adds a real-time stream of PR events that Cortex cross-references against API data, which is the most efficient way to ensure every PR and event is captured without gaps.

**If you use the Cortex GitHub app, no action is required**. The Cortex GitHub app receives these PR webhook events by default, so you get real-time PR data out of the box.

**If you use a custom GitHub app or a personal access token (PAT)**, you must subscribe to the following events manually at the repository or organization level:

* Pull requests
* Pull request reviews
* Pull request review comments
* Pull request review threads
* Issue comments (GitHub delivers PR comments as issue-comment events)
* Organizations
* Repositories

For a custom GitHub app, select the above events under your app's **Permissions & events > Subscribe to events**, then click **Save**.&#x20;

For a PAT connection, add the above events to your Cortex webhook under the repository or organization's **Settings > Webhooks**.

Cortex begins receiving PR webhook events immediately and automatically cross-references them against standard API ingestion to validate the data.

### Choosing a configuration option

There are multiple options for connecting Cortex to your GitHub instance:

* Through Cortex's official GitHub app
  * This option is supported for use with a single organization in GitHub.
* Through a custom GitHub app
  * By using Cortex's official GitHub app or a custom GitHub app, users can tag entities with Git details and enable GitOps-style configuration of data in Cortex.
* Using a personal access token
* Using Cortex Axon Relay, a relay broker that allows you to securely connect your on-premises GitHub data.

If your GitHub setup involves multiple organizations, you can add multiple GitHub apps, use a [personal access token](#configuration---personal-access-token) that has access to all orgs, or create multiple configurations with corresponding aliases.

See the tabs below for instructions on each of the GitHub integration options.

{% hint style="info" %}
If you're using a self-hosted instance of GitHub, you'll need to verify that your Cortex instance is able to reach the GitHub instance. Requests are routed through a static IP address.

Contact support at <help@cortex.io> to receive details about our static IP. If you're unable to directly allowlist our static IP, you can route requests through a secondary proxy in your network that has this IP allowlisted and have that proxy route traffic to your GitHub instance.
{% endhint %}

{% tabs %}
{% tab title="Cortex GitHub app" %}
**Configure GitHub with the Cortex GitHub app**

[Cortex's official GitHub app](https://github.com/apps/cortex-app) is the easiest way to connect your GitHub instance. It is preconfigured with the [permissions](#prerequisites) needed to use this integration. Note that it is not available for Cortex Server.

To set up the app:

1. In Cortex, navigate to the [GitHub settings page](https://app.getcortexapp.com/admin/integrations/github):
   1. Click **Integrations** from the main nav. Search for and select **GitHub**.
2. On the GitHub settings page, next to `cortex`, click **Install**.\
   ![](/files/2YjpsIRrU7NaEMpCr9kT)
3. Follow the prompts, then click **Install & Authorize**.

Cortex's GitHub app is preconfigured with:

* Permissions for [catalogs](/ingesting-data-into-cortex/catalogs), [Scorecards](/standardize/scorecards), and the [Scaffolder](/streamline/workflows#scaffolder).
* Webhooks to enable [GitOps](/configure/gitops).
* Support for using [GitHub teams](https://docs.github.com/en/organizations/organizing-members-into-teams/about-teams) as an ownership provider.

The app comes with a built-in linter, which validates the format of a given `cortex.yaml` file and checks Cortex-specific items. **However, the linter DOES NOT validate data correctness.** For example, the linter will confirm that the format of a group block is correct, but will not check that the group exists.
{% endtab %}

{% tab title="Custom app" %}
**Configure GitHub with a custom app**

If you're using Cortex Server, or if you don't want to use the official Cortex app, you can connect a custom GitHub app.

Make sure you have configured the permissions listed above under [Prerequisites](#prerequisites).

**Step 1: Register the custom app in GitHub**

1. [Register the app](https://docs.github.com/en/apps/creating-github-apps/registering-a-github-app/registering-a-github-app). When you're creating the app, make sure to follow these steps:
   * **Disable** "Expire user authorization tokens." (Cortex does not support this OAuth workflow yet.)
   * **Select** "Request user authorization (OAuth) during installation."
   * **Callback URL:** `https://app.getcortexapp.com/github/redirect/{alias}`
     * Make sure to use the GitHub configuration alias and not the tenant name in the URL.
   * **Webhook URL:** `https://api.getcortexapp.com/api/internal/v1/github/webhook`
   * **Add** a webhook secret of your choosing that will be identical to the webhook secret token configured later in Cortex settings.
   * **Set** the repository and organization [permissions](#api-permissions) outlined in the configuration modal.
   * **Check** `Push` and `Check suite` under **Subscribe to events**.
2. After the app has been created, generate a client secret and private key.

**Step 2: Configure the custom app in Cortex**

1. In Cortex, navigate to the [GitHub settings page](https://app.getcortexapp.com/admin/integrations/github):
   * Click **Integrations** from the main nav. Search for and select **GitHub**.
2. Click **Add configuration**, then for the type, select **GitHub app**.
3. Fill in the form:
   * **Alias:** Enter the name Cortex will associate with a given configuration.
   * **Application ID:** Enter the ID for your custom GitHub ap.
   * **Client ID:** Enter the unique [client ID](https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/authenticating-to-the-rest-api-with-an-oauth-app#registering-your-app) assigned to your app during registration.
   * **Client secret:** Enter the unique client secret assigned to your app during registration.
   * **Private key:** Enter the [private key](https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/managing-private-keys-for-github-apps#generating-private-keys) to authenticate with your GitHub app.
   * **Public link:** Enter the public URL of your GitHub app.
   * **API endpoint (for GitHub enterprise):** Enter the endpoint root URL for self-managed GitHub setups.
4. Click **Save**.
5. On the GitHub Settings page in Cortex, under **Webhook**, choose your new configuration alias and enter the same **Secret token** that was entered in GitHub during the app configuration.
6. On the GitHub Settings page in Cortex, next to your custom app configuration's name, click **Install**.
   {% endtab %}

{% tab title="Personal access token" %}
**Configure GitHub with a personal access token**

**Prerequisites**

Before getting started, make sure your [personal access token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens) has, at minimum, the `repo` and `read:org` permissions.

Note: Beyond the minimum permissions indicated above, many scenarios will require that the user who generated the personal access token have organization ownership permissions within GitHub.

**Configuration**

1. In Cortex, navigate to the [GitHub settings page](https://app.getcortexapp.com/admin/integrations/github):
   * Click **Integrations** from the main nav. Search for and select **GitHub**.
2. Click **Add configuration**.
3. In the upper right corner of the modal, click the dropdown and select **Personal access token**.

   <figure><img src="/files/ZmKO27g2EwJnihbtyTU4" alt=""><figcaption></figcaption></figure>
4. Fill in the form:
   * **Alias:** Enter a name that Cortex will associate with a given configuration.
   * **Token:** Enter the Personal access token generated in GitHub.
   * **API endpoint (for GitHub enterprise):** Enter the endpoint root URL for self-managed GitHub setups.
5. Click **Save**.
   {% endtab %}

{% tab title="Relay broker" %}
**Configure GitHub with Cortex Axon Relay**

See [Internally hosted integrations](/ingesting-data-into-cortex/integrations/axon-relay) for instructions. Make sure to follow the GitHub-specific instructions for the docker-compose.yml file.
{% endtab %}
{% endtabs %}

#### **Configuring the integration for multiple GitHub accounts**[**​**](https://docs.cortex.io/docs/reference/integrations/github#configure-the-integration-for-multiple-propsintegration-accounts)

The GitHub integration has multi-account support. You can add a configuration for each additional organization, instance, or account by repeating the process above.

Each configuration requires an alias, which Cortex uses to correlate the designated organization, instance, or account with registrations for various entities. Registrations can also use a default configuration without a listed alias. You can edit aliases and default configurations from the GitHub page in your Cortex settings.

**To set the default configuration**:

1. From the main sidebar, select **Integrations**.
2. Locate GitHub, then click **Settings**.
3. Locate the configuration, then click the **pencil icon**.
4. From the **Category** drop-down menu, select a category. You must select at least one category before you can set the configuration as default.
5. Toggle on **Set as default**.\
   \> **Tip**: If you only have one configuration, it's automatically set as the default.

Cortex supports mapping multiple identities for a single user if you have multiple configurations of GitHub. See [Configuring identity mappings](/configure/settings/managing-users/identity-mapping) for more information.

{% hint style="info" %}
To write rules related to Dependabot alerts, you must verify the necessary permissions are set for repositories you'd like to see vulnerabilities reported on.

To verify, navigate to a GitHub repo and click **Settings > Code security and analysis**. Ensure you are a member of a team under **Access to alerts**.
{% endhint %}

## Registration

See the [Create services documentation](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/add-services#creating-services) for instructions on importing entities.

### Entity descriptor

**Repository**

You can define a GitHub repository for a given entity by adding the `x-cortex-git` block to the entity's descriptor. When you define a repository, Cortex checks for Security Advisory vulnerabilities from the GraphQL API and Advanced Security vulnerabilities from the Rest API.

```yaml
x-cortex-git:
  github:
    repository: cortex/docs
    basepath: myService
    alias: myApp
```

<table><thead><tr><th width="137.26953125">Field</th><th width="504.16796875">Description</th><th align="center">Required</th></tr></thead><tbody><tr><td><code>repository</code></td><td>GitHub repository in the form <code>/</code></td><td align="center"><strong>✓</strong></td></tr><tr><td><code>basepath</code></td><td>Subdirectory for the entity if it is in a monorepo. Note that setting a <code>basepath</code> filters the vulnerabilities that appear in Cortex; Advanced Security vulnerabilities will not appear.</td><td align="center"></td></tr><tr><td><code>alias</code></td><td>Alias for the configuration in Cortex (only needed if you have opted into multi-account support)</td><td align="center"></td></tr></tbody></table>

Only one repository can be defined for in a given entity's YAML in the `x-cortex-git` block. Users looking to list additional repositories without the full functionality of GitOps can define the repos as custom data.

```yaml
x-cortex-custom-metadata:
  second-git-repo:
    - `/`
  third-git-repo:
    - `/`
```

**Ownership**

You can define the following block in your Cortex entity descriptor to add your GitHub teams. Be sure to include both your GitHub organization name and the team name in the `name` field.

```yaml
x-cortex-owners:
  - type: group
    name: cortex/engineering
    provider: GITHUB
    description: This is a description for this GitHub team that owns this entity.
```

| Field         | Description                                                                                                                                                                                                 | Required |
| ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------: |
| `type`        | Ownership type; must be defined as `group` for GitHub teams                                                                                                                                                 |   **✓**  |
| `name`        | GitHub team name in the form `/`Team names are generally converted to lowercase with `-` separators (`Team Name` would be `cortex/team-name`), but you can verify your exact name from the GitHub permalink |   **✓**  |
| `provider`    | Name of integration (in this case, `GITHUB`)                                                                                                                                                                |   **✓**  |
| `description` | Description for the GitHub team                                                                                                                                                                             |          |

{% hint style="warning" %}
Multiple GitHub organizations are not supported for ownership, and Cortex will use the default configuration when fetching teams.
{% endhint %}

### Identity mappings

Cortex maps users' email addresses to discovered GitHub accounts, so you never need to define email ownership in an entity descriptor. Users must be members of GitHub teams to be pulled in to Cortex.

You can confirm users' GitHub accounts are connected from [GitHub identity mappings in settings](https://app.getcortexapp.com/admin/settings/github-mappings).

## Using the GitHub integration

### View GitHub data on entity pages in Cortex

The GitHub integration will populate the **Repo** and **Language** detail blocks on an [entity's details page](/ingesting-data-into-cortex/entities-overview/entities/details). If a GitHub team has been [defined as the owner](#ownership) for an entity, it will also appear in the **Owners** block.

#### Code & security

Vulnerabilities appear in the **Vulnerabilities** block under **Code & security** on an entity page overview.

Click **Code & security** in an entity's sidebar to view the full list of vulnerabilities for an entity. Cortex checks for:

* Security Advisory vulnerabilities from the GraphQL API
* [GitHub Advanced Security](https://docs.github.com/en/get-started/learning-about-github/about-github-advanced-security) vulnerabilities
  * Cortex pulls data from code scanning, Dependabot alerts, CodeQL, and Secret scanning.
  * Dependency reviews are not supported.

GitHub Advanced Security vulnerabilities are not surfaced for monorepos.

{% hint style="success" %}
You can query for vulnerabilities with CQL and create Scorecard rules based on security metrics. See [Scorecards and CQL](#scorecards-and-cql) below.
{% endhint %}

#### **Events**

Recent commits appear at the top of an entity's overview page.

You can also click **Events** in the entity's sidebar to see all commits and releases associated with that entity. Each is hyperlinked to the commit or release page in GitHub and includes a timestamp.

#### **Repository**

You can access more detailed information pulled from GitHub in the **Repository** page in the sidebar. At the top of the page, you'll find the repo(s) associated with that entity and the most-used language in files for that entity. In the **Top contributors** block, you'll find the three users who have contributed the most code and the number of their contributions.

In the **Commits** section, you'll find the 10 most recent commits and metadata about each. Below **Commits** is the **Recent releases** section, which includes the 5 most recent releases.

#### **Issue tracking**

From the **Issue tracking** page in the entity's sidebar, you can find a list of open [GitHub issues](https://docs.github.com/en/issues). Each issue will show the number, title, assignees, and date created.

#### **Packages**

Packages are automatically scraped from your Git repos or they can be submitted via the [packages API](/api/readme/packages). The package file must be in the root of your repository — or, if you're using `basepath`, in the root of the subdirectory — to be scraped by Cortex. You can query an entity's packages in [CQL explorer](https://app.getcortexapp.com/admin/cql-explorer) using `packages()`.

To view packages, click **Packages** in the entity's sidebar.

The following package types are automatically scraped from repositories:

* JavaScript / Node.js: `package.json`, `package-lock.json`, `yarn.lock`, `pnpm-lock.yaml`
* Python: `requirements.txt`, `pipfile.lock`
* .NET (C#): `packages.lock.json`
* Java: `pom.xml`
* Go: `go.sum`

All other files of these types can be added via the [packages API](/api/readme/packages).

#### **CI/CD - GitHub workflows**

From the **CI/CD > GitHub workflows** page in the entity's sidebar, you can find a history of [GitHub workflow](https://docs.github.com/en/actions/using-workflows/about-workflows) runs for the past week. Each run is tagged with its status: `IN_PROGRESS`, `COMPLETED`, `SUCCESS`, `CANCELLED`, `FAILURE`, `PAUSED`.

The **GitHub workflows** page displays data about workflows in GitHub, **not** Workflows initiated via [Cortex's Workflows tool](/streamline/workflows).

### Team entity pages

When a [GitHub team is registered](#ownership) with a team entity, Cortex will pull GitHub users in to the **Members** tab. When available, Cortex will pull in the profile picture and email address for each user.

### Engineering homepage

The GitHub integration enables Cortex to pull information about pull requests and issues into the [homepage](/streamline/homepage). You can find your open pull requests, any pull requests assigned to you for review, and any issues assigned to you.

Pull requests and issues from GitHub are refreshed every 2 minutes.

### Eng Intelligence

The [Eng Intelligence tool](/improve/eng-intelligence) uses pull request data from GitHub to generate metrics:

* Average PR open to close time
* Avg time to first review
* Avg time to approval
* PRs opened
* Weekly PRs merged
* Avg PRs reviewed/week
* Avg commits per PR
* Ave lines of code changed per PR

Eng Intelligence also pulls in data from Copilot to show AI impact in the [Copilot Dashboard](/improve/eng-intelligence/dashboards/ai-impact).

You can read more about how Eng Intelligence tracks metrics for teams and users in the [Eng Intelligence documentation](/improve/eng-intelligence).

To add deployments for your Github related entity, you can send a deployment event to the [Cortex API.](/api/readme/deploys)

### Bot-authored pull requests and reviews

Some pull requests and reviews in GitHub come from bot accounts, like Dependabot or a GitHub App that a team set up. Cortex ingests this activity along with everything else and attributes it to the bot that produced it, so you can include or exclude it deliberately.

**How Cortex identifies a bot**

Cortex uses the account type that GitHub reports. If GitHub identifies the account as a bot, Cortex marks its pull requests and reviews as bot generated. Automation that runs under a regular GitHub user account isn't marked as bot generated, because GitHub reports that account as a user.

**Where bot accounts appear**

* A pull request opened by a bot shows that bot's account name as the author, for example `dependabot[bot]`, rather than an empty author.
* In Eng Intelligence, bot accounts appear alongside people in the **User** filter and group-by options, so you can single out or exclude a specific bot.
* Eng Intelligence metric values don't change. These pull requests were always counted, so all that's new is the author attribution.

**Filtering bot activity in CQL**

`git.pullRequests()` and `git.reviews()` return bot activity by default. `GitPullRequest` and `GitReview` each have a `botGenerated` field, which is `true` when GitHub reports the account as a bot.

To count only the pull requests opened by people:

```
git.pullRequests(lookback=duration("P14D")).filter((pr) => !pr.botGenerated).length > 0
```

To look at automated review activity on its own:

```
git.reviews(lookback=duration("P7D")).filter((review) => review.botGenerated).length > 0
```

**Availability**

Cortex began marking bot activity on August 18, 2026. Pull requests and reviews that Cortex ingested before then have `botGenerated` set to `false`, even when a bot produced them, so a query with a long lookback period can undercount bot activity.

### Scorecards and CQL

With the GitHub integration, you can create Scorecard rules and write CQL queries based on GitHub data.

See more examples in the [CQL Explorer](https://app.getcortexapp.com/admin/cql-explorer) in Cortex.

<details>

<summary>Approvals required to merge</summary>

Number of approvals required to merge a pull/merge request into a repository. Defaults to 0 if no approvals are defined.

**Definition**: `git.numOfRequiredApprovals()`

**Examples**

For a security or development maturity Scorecard, you can write a rule to make sure at least one approval is required to merge a pull/merge request:

```
git.numOfRequiredApprovals() > 0
```

By having a rigorous PR process in place for a repo, you can make sure changes aren't made that create vulnerabilities. This kind of rule could also be used in a best practices or project standards Scorecard.

You can also use a similar expression in the Query Builder to find entities lacking approval:

```
git.numOfRequiredApprovals() < 1
```

</details>

<details>

<summary>Git repository set</summary>

Check if an entity has a registered Git repository.

**Definition:** `git (==/!=) null: Boolean`

**Example**

In a Scorecard, you can write a rule that detects whether an entity has a Git repository set:

```
git != null
```

</details>

<details>

<summary>Branches</summary>

List all live branches with some basic metadata.

* Head
* Is protected
* Name

**Definition**: `git.branches()`

**Example**

For a best practices Scorecard, you can make sure that branches associated with an entity match a standard naming convention:

```
git.branches().all((branch) => branch.name.matches("(main|master|feat-.*|bug-.*|task-.*)"))
```

</details>

<details>

<summary>Branch protection details</summary>

{% hint style="info" %}
`git.branchProtection()` now returns the **effective** branch protection for a branch by merging policies from both classic branch protection and GitHub rulesets into a unified view. This means it reflects what GitHub actually enforces, regardless of whether a repo uses classic rules, rulesets, or a combination of both.
{% endhint %}

Find details for specified branch, or default branch if none is specified.

* Branch name
* Code owner reviews required
* Dismiss stale reviews
* Required status checks
* Restrictions apply to admin
* Review required

**Definition:** `git.branchProtection()`

**Examples**

For a security Scorecard, you can write a rule to make sure the default branch is protected:

```
git.branchProtection() != null
```

Because vulnerabilities in the default branch are critical, this rule should be in one of the first couple levels.

You can also use the Query Builder to find entities with unprotected default branches:

```
git.branchProtection() = null
```

</details>

<details>

<summary>Branch rulesets</summary>

GitHub [branch rulesets](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-rulesets) are a newer, more flexible alternative to classic branch protection. Rulesets are layered (organization + repository), composed of typed rules, and can target multiple branches by pattern. Cortex exposes them in CQL through `git.branchRulesets(...)`.

`git.branchRulesets(branchName?)` returns the effective ruleset for a branch, i.e. the rules from every active ruleset that targets that branch, merged together. Pass a branch name to target a specific branch; omit it to use the repo's default branch. Returns `null` if no ruleset applies.

```
git.branchRulesets().rules.any((rule) =>
    rule.type == "pull_request" && rule.requiredApprovingReviewCount >= 2
)
```

```
// Require Copilot code review on push for the default branch
git.branchRulesets().rules.any((rule) =>
    rule.type == "copilot_code_review" && rule.reviewOnPush == true
)
```

```
// Forbid pushes that match a banned commit-message pattern
git.branchRulesets().rules.any((rule) =>
    rule.type == "commit_message_pattern" && rule.patternOperator == "regex"
)
```

`GitBranchRulesets` **fields**

<table><thead><tr><th width="159.0234375">Field</th><th width="230.125">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>branchName</code></td><td><code>String</code></td><td>Branch the rules apply to.</td></tr><tr><td><code>rules</code></td><td><code>List&#x3C;GitBranchRule></code></td><td>All effective rules for the branch.</td></tr></tbody></table>

`GitBranchRule` **common fields**

Present on every rule regardless of `type` .

<table><thead><tr><th width="184.2734375">Field</th><th width="106.6484375">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td><code>String</code></td><td>Rule type. See sections below for the full list.</td></tr><tr><td><code>rulesetSourceType</code></td><td><code>String</code></td><td>Source level: <code>Repository</code>, <code>Organization</code>, or <code>Enterprise</code>.</td></tr><tr><td><code>rulesetSource</code></td><td><code>String</code></td><td>Owner (for org), repo full name (for repository), or enterprise slug.</td></tr><tr><td><code>rulesetId</code></td><td><code>Long</code></td><td>GitHub ID of the ruleset this rule came from.</td></tr></tbody></table>

All remaining fields below are nullable; only the fields associated with a rule's `type` are populated, and the rest are `null`.

Rule type: `pull_request`

| Field                            | Type                                   | Description                                                             |
| -------------------------------- | -------------------------------------- | ----------------------------------------------------------------------- |
| `requiredApprovingReviewCount`   | `Int?`                                 | Minimum approvals required.                                             |
| `dismissStaleReviewsOnPush`      | `Boolean?`                             | Dismiss prior approvals when new commits land.                          |
| `requireCodeOwnerReview`         | `Boolean?`                             | Require code-owner approval.                                            |
| `requireLastPushApproval`        | `Boolean?`                             | The most-recent push must be approved by someone other than the pusher. |
| `requiredReviewThreadResolution` | `Boolean?`                             | All review threads must be resolved before merging.                     |
| `allowedMergeMethods`            | `List<String>?`                        | One or several of `merge`, `squash`, `rebase`.                          |
| `requiredReviewers`              | `List<RequiredReviewerConfiguration>?` | (Beta) Reviewers required for changes matching specific file patterns.  |

Rule type: `required_status_checks`

<table><thead><tr><th width="256.515625">Field</th><th width="150.2890625">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>requiredStatusCheckContexts</code></td><td><code>List&#x3C;String>?</code></td><td>Required check names.</td></tr><tr><td><code>strictRequiredStatusChecksPolicy</code></td><td><code>Boolean?</code></td><td>Branch must be up-to-date before merging.</td></tr><tr><td><code>doNotEnforceOnCreate</code></td><td><code>Boolean?</code></td><td>Allow repos/branches to be created even if a check would prohibit it. (Also populated for <code>workflows</code>.)</td></tr></tbody></table>

Rule type: `required_deployments`

<table><thead><tr><th>Field</th><th width="159.62890625">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>requiredDeploymentEnvironments</code></td><td><code>List&#x3C;String>?</code></td><td>Required environment deployments.</td></tr></tbody></table>

Rule type: `update`

<table><thead><tr><th width="251.28515625">Field</th><th width="97.77734375">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>updateAllowsFetchAndMerge</code></td><td><code>Boolean?</code></td><td>Branch can pull changes from its upstream repository.</td></tr></tbody></table>

Rule type: `merge_queue`

<table><thead><tr><th width="256.828125"></th><th width="99.140625"></th><th></th></tr></thead><tbody><tr><td><code>mergeQueueCheckResponseTimeoutMinutes</code></td><td><code>Int?</code></td><td>Max time a required check has to report a conclusion before being considered failed.</td></tr><tr><td><code>mergeQueueGroupingStrategy</code></td><td><code>String?</code></td><td><code>ALLGREEN</code> or <code>HEADGREEN</code>.</td></tr><tr><td><code>mergeQueueMaxEntriesToBuild</code></td><td><code>Int?</code></td><td>Maximum queued PRs being checked/built simultaneously.</td></tr><tr><td><code>mergeQueueMaxEntriesToMerge</code></td><td><code>Int?</code></td><td>Maximum PRs merged together in one group.</td></tr><tr><td><code>mergeQueueMergeMethod</code></td><td><code>String?</code></td><td><code>MERGE</code>, <code>SQUASH</code>, or <code>REBASE</code>. (Uppercase here; lowercase on <code>allowedMergeMethods</code>.)</td></tr><tr><td><code>mergeQueueMinEntriesToMerge</code></td><td><code>Int?</code></td><td>Minimum PRs in a merge group.</td></tr><tr><td><code>mergeQueueMinEntriesToMergeWaitMinutes</code></td><td><code>Int?</code></td><td>Minutes to wait before merging a smaller-than-minimum group.</td></tr></tbody></table>

**Pattern rule types**

Shared by `commit_message_pattern`, `commit_author_email_pattern`, `committer_email_pattern`, `branch_name_pattern`, `tag_name_pattern`. The same four fields are populated for any of these.

<table><thead><tr><th width="169.78515625">Field</th><th width="126.8984375">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>patternName</code></td><td><code>String?</code></td><td>Display name for the pattern rule.</td></tr><tr><td><code>patternNegate</code></td><td><code>Boolean?</code></td><td>If <code>true</code>, the rule fails when the pattern matches.</td></tr><tr><td><code>patternOperator</code></td><td><code>String?</code></td><td><code>starts_with</code>, <code>ends_with</code>, <code>contains</code>, or <code>regex</code>.</td></tr><tr><td><code>pattern</code></td><td><code>String?</code></td><td>The pattern to match against.</td></tr></tbody></table>

Rule type: `workflows`

| Field                  | Type                           | Description                                       |
| ---------------------- | ------------------------------ | ------------------------------------------------- |
| `requiredWorkflows`    | `List<WorkflowFileReference>?` | Workflows that must pass for the rule to pass.    |
| `doNotEnforceOnCreate` | `Boolean?`                     | Shared with `required_status_checks` . See above. |

Rule type: `code_scanning`

| Field               | Type                      | Description                                    |
| ------------------- | ------------------------- | ---------------------------------------------- |
| `codeScanningTools` | `List<CodeScanningTool>?` | Tools that must provide code-scanning results. |

Rule type: `copilot_code_review`

<table><thead><tr><th>Field</th><th width="137.58203125">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>reviewDraftPullRequests</code></td><td><code>Boolean?</code></td><td>Copilot reviews draft PRs before they're marked ready.</td></tr><tr><td><code>reviewOnPush</code></td><td><code>Boolean?</code></td><td>Copilot reviews every new push.</td></tr></tbody></table>

Rule type: `file_path_restriction`

<table><thead><tr><th width="215.7109375">Field</th><th width="171.08203125">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>restrictedFilePaths</code></td><td><code>List&#x3C;String>?</code></td><td>File paths restricted from being pushed.</td></tr></tbody></table>

Rule type: `max_file_path_length`

<table><thead><tr><th width="202.15625">Field</th><th width="108.203125">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>maxFilePathLength</code></td><td><code>Int?</code></td><td>Maximum number of characters allowed in file paths.</td></tr></tbody></table>

Rule type: `file_extension_restriction`

<table><thead><tr><th width="239.515625">Field</th><th width="142.22265625">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>restrictedFileExtensions</code></td><td><code>List&#x3C;String>?</code></td><td>File extensions restricted from being pushed.</td></tr></tbody></table>

Rule type: `max_file_size`

<table><thead><tr><th width="142.94140625">Field</th><th width="122.71484375">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>maxFileSize</code></td><td><code>Int?</code></td><td>Maximum file size in megabytes (excluding Git LFS).</td></tr></tbody></table>

**Rule types without parameters**

`creation`, `deletion`, `required_linear_history`, `non_fast_forward`, and `required_signatures` present in the rules list with only the common fields populated.

**Nested types**

`RequiredReviewerConfiguration` - each element of `pull_request.requiredReviewers`:

<table><thead><tr><th width="171.296875">Field</th><th width="165.046875">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>filePatterns</code></td><td><code>List&#x3C;String></code></td><td>fnmatch patterns — PRs that change matching files require this reviewer.</td></tr><tr><td><code>minimumApprovals</code></td><td><code>Int</code></td><td>Required approvals from this reviewer. Zero makes approval optional but still adds the reviewer.</td></tr><tr><td><code>reviewer</code></td><td><code>RulesetReviewer</code></td><td>The reviewing team.</td></tr></tbody></table>

`RulesetReviewer` - nested in `RequiredReviewerConfiguration.reviewer`:

<table><thead><tr><th width="175.43359375">Field</th><th width="168.36328125">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>id</code></td><td><code>Long</code></td><td>Reviewer ID.</td></tr><tr><td><code>type</code></td><td><code>String</code></td><td>Reviewer kind. Currently always <code>Team</code>.</td></tr></tbody></table>

`WorkflowFileReference` - each element of `workflows.requiredWorkflows`:

<table><thead><tr><th width="154.12109375">Field</th><th width="124.828125">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>path</code></td><td><code>String</code></td><td>Path to the workflow file in the repository.</td></tr><tr><td><code>ref</code></td><td><code>String?</code></td><td>Branch or tag ref of the workflow file to use.</td></tr><tr><td><code>repositoryId</code></td><td><code>Long</code></td><td>ID of the repository where the workflow is defined.</td></tr><tr><td><code>sha</code></td><td><code>String?</code></td><td>Commit SHA of the workflow file to use.</td></tr></tbody></table>

`CodeScanningTool` - each element of `code_scanning.codeScanningTools`:

<table><thead><tr><th width="240.10546875"></th><th width="127.66015625"></th><th></th></tr></thead><tbody><tr><td><code>alertsThreshold</code></td><td><code>String</code></td><td>Severity at which alerts block a push: <code>none</code>, <code>errors</code>, <code>errors_and_warnings</code>, <code>all</code>.</td></tr><tr><td><code>securityAlertsThreshold</code></td><td><code>String</code></td><td>Severity at which security alerts block: <code>none</code>, <code>critical</code>, <code>high_or_higher</code>, <code>medium_or_higher</code>, <code>all</code>.</td></tr><tr><td><code>tool</code></td><td><code>String</code></td><td>Name of the code-scanning tool.</td></tr></tbody></table>

**Relationship with** `git.branchProtection()`

`git.branchProtection()` returns the **effective** branch protection for a branch, merging policies from both classic branch protection and GitHub rulesets into a unified result. `git.branchRulesets()` remains available if you need granular access to individual ruleset rules (e.g. filtering by type, source, or ruleset ID).

</details>

<details>

<summary>Commits</summary>

Get the latest commits **(to a maximum of 100)** for a defined lookback period **(defaulting to 7 days)**.

* Date
* Message
* SHA
* URL
* Username

These results can be filtered based on branch name, using the default branch if no other branch is provided.

**Definition:** `git.commits()`

**Example**

You can use the `git.commits()` expression in a security Scorecard to make sure entities have fewer than three commits to a "security-fixes" branch in the last week:

```
git.commits(branchName="security-fixes").length < 3
```

Entities passing this rule will include those that haven't needed three or more security fixes. This can indicate that there aren't vulnerabilities in a given entity's code, but could also suggest that fixes aren't being implemented. Using this rule in conjunction with one focused on vulnerabilities could provide the extra context needed to gain a better understanding of what's happening.

</details>

<details>

<summary>Default branch</summary>

Default branch for the repository, or `main` when null.

**Definition:** `git.defaultBranch()`

**Example**

If default branches should always be named "main," you can write a rule to make sure entities follow this practice:

```
git.defaultBranch().matches("main")
```

</details>

<details>

<summary>File contents</summary>

Load the contents of a file from the entity's associated repository.

The contents can be validated by using string comparison operations or parsed by the built-in jq function. The jq function will automatically coerce file contents of JSON or YAML formats.

**Definition:** `git.fileContents()`

**Example**

For a Scorecard focused on development maturity, you could use the `git.fileContents()` rule to enforce that a CI pipeline exists, and that there is a testing step defined in the pipeline.

```
git.fileContents("circleci/config.yml").matches(".*npm test.*")
```

A best practices Scorecard, meanwhile, could use this expression for a number of rules:

* To make sure node engine version in specified in the `package.json` file:

  ```
  jq(git.fileContents("package.json"), ".engines.node") != null
  ```
* To make sure TypeScript projects have a `tsconfig.json` file checked in:

  ```
  jq(git.fileContents("package.json"), ".devDependencies | with_entries(select(.key == \"typescript\")) | length") == 0 or git.fileExists("tsconfig.json")
  ```
* To make sure projects using yarn do not allow NPM:

  ```
  jq(git.fileContents("package.json"), ".engines.yarn") == null or jq(git.fileContents("package.json"), ".engine.npm") = "please-use-yarn"
  ```
* And to ensure the yarn version being used is not deprecated:

  ```
  jq(git.fileContents("package.json"), ".engines.yarn") == null or !(semver("1.2.0") ~= semverRange(jq(git.fileContents("package.json"), ".engines.yarn")))
  ```

</details>

<details>

<summary>File exists</summary>

Check if file exists from within the entity's associated repository.

**Definition:** `git.fileExists()`

**Examples**

For a Scorecard focused on best practices, you can make sure that repositories contain a README.md file:

```
git.fileExists("README.md")
```

This rule would make sense in the first level because it's so essential.

A higher-level rule in a best practices Scorecard might confirm that developers are checking in lockfiles to ensure consistency in package installs:

```
git.fileExists("yarn.lock") OR git.fileExists("package-lock.json")
```

And/or a rule that makes sure there are unit tests enabled:

```
git.fileExists("*Test.java")
```

Finally, you could write a rule to make sure projects have a standard linter:

```
git.fileExists(".prettierrc.json") OR git.fileExists(".eslintrc.js")
```

</details>

<details>

<summary>Number of Git vulnerabilities</summary>

Check the number of vulnerabilities for an entity's associated repository.

You can filter by severity (by default searches by all severities) or source (by default only searches GitHub security advisories).

**When using the GitHub Advanced Security source, severities displayed in the UI may not match severities returned by the API.**

**Definition:** `git.numOfVulnerabilities()`

**Examples**

A security-focused Scorecard will likely include a rule making sure there are no Git vulnerabilities:

```
git.numOfVulnerabilities() == 0
```

You can use Scorecard levels to stratify vulnerabilities by risk. An initial level might make sure there are no critical vulnerabilities:

```
git.numOfVulnerabilities(severity=["CRITICAL"]) == 0
```

While a higher level might make sure there are no vulnerability warnings:

```
git.numOfVulnerabilities(severity=["WARNING"]) == 0
```

</details>

<details>

<summary>List of Git vulnerabilities</summary>

Lists the vulnerabilities for an entity's associated repository. You can filter by severity (by default searches by all severities) or source (by default only searches GitHub security advisories). Note when using the GitHub Advanced Security source, severities displayed in the UI may not match severities returned by the API.

**Definition**: `git.vulnerabilities()`

**Examples**

You could write a Scorecard rule that verifies an entity has fewer than 5 Git vulnerabilities:

```
git.vulnerabilities().length < 5
```

You could write a rule that verifies the entity has no vulnerabilities with "High" or "Critical" severity sourced from GitHub Advanced Security:

```
git.vulnerabilities(severity=["CRITICAL", "HIGH"], source=["GITHUB_ADVANCED_SECURITY"]).length < 1
```

</details>

<details>

<summary>Has Cortex YAML</summary>

Check if a repository has a valid `cortex.yaml` file checked in at the root directory (when GitOps is enabled).

**Definition:** `git.hasCortexYaml()`

**Example**

If you're using a Scorecard to track a migration from Cortex UI to GitOps, you can use this rule to make sure entities are set up for GitOps management of entity descriptors:

```
git.hasCortexYaml() == true
```

</details>

<details>

<summary>Last commit details</summary>

Provides last commit details.

* Date
* Message
* SHA
* URL
* Username

**Definition:** `git.lastCommit()`

**Examples**

One of the first rules you might write for a Scorecard focused on development maturity or security is one validating that the last commit was within the last month:

```
git.lastCommit().freshness < duration("P1M")
```

As counterintuitive as it may seem, services that are committed too infrequently are actually at more risk. People who are familiar with the service may leave a team, institutional knowledge accumulates, and from a technical standpoint, the service may be running outdated versions of your platform tooling.

Depending on best practices at your organization, you may want to confirm entities are updated within a week:

```
git.lastCommit().freshness < duration("P7D")
```

Confirming whether a service was updated within the last week can help team members catch outdated code sooner. Plus, if there is a security issue, you can quickly determine which services have or have not been updated to patch the vulnerability.

</details>

<details>

<summary>Pull requests</summary>

Lists the pull requests opened during a defined lookback period. Bot-authored pull requests are included by default, so filter them out if you only want activity from people.

Each pull request has these properties:

<table><thead><tr><th width="181.859375">Property</th><th>Description</th></tr></thead><tbody><tr><td>Approval date</td><td>When the pull request was approved.</td></tr><tr><td>Author</td><td>The GitHub user account or bot account that opened the pull request.</td></tr><tr><td>Bot generated</td><td>Whether a bot account opened the pull request. Written as <code>botGenerated</code> in CQL.</td></tr><tr><td>Date closed</td><td>When the pull request was closed.</td></tr><tr><td>Date opened</td><td>When the pull request was opened.</td></tr><tr><td>First review date</td><td>When the pull request received its first review.</td></tr><tr><td>Is draft</td><td>Whether the pull request is still a draft. Written as <code>isDraft</code> in CQL.</td></tr><tr><td>Last updated</td><td>When the pull request last changed.</td></tr><tr><td>Number of commits</td><td>How many commits the pull request contains.</td></tr><tr><td>Number of lines added</td><td>How many lines the pull request adds.</td></tr><tr><td>Number of lines deleted</td><td>How many lines the pull request deletes.</td></tr><tr><td>Organization</td><td>The GitHub organization that owns the repository.</td></tr><tr><td>Repository</td><td>The repository the pull request belongs to.</td></tr><tr><td>Source</td><td>The Git provider the pull request came from.</td></tr><tr><td>Status</td><td>The current state of the pull request, such as open, closed, or merged.</td></tr><tr><td>URL</td><td>A link to the pull request in GitHub.</td></tr></tbody></table>

**Definition** - `git.pullRequests(lookback: Duration)`

**Example**

Use the `git.pullRequests()` expression to find entities with very few pull requests opened in the last two weeks:

```
git.pullRequests(lookback=duration("P14D")).length < 3
```

This surfaces entities that nobody has touched lately, which is useful when you need to confirm that a fix, like a vulnerability patch, is actually being picked up.

**Example**

Filter out drafts to count only the pull requests that are ready for review:

```
git.pullRequests(lookback=duration("P14D")).filter((pr) => !pr.isDraft).length < 3
```

**Example**

Filter out bot accounts to count only the pull requests opened by people:

```
git.pullRequests(lookback=duration("P14D")).filter((pr) => !pr.botGenerated).length < 3
```

Reverse the filter to `pr.botGenerated` to look at automated activity on its own, for example to see how much of a repository's pull request volume comes from dependency bots.

</details>

<details>

<summary>Reviews</summary>

Lists the reviews left during a defined lookback period. Reviews left by bots are included by default, so filter them out if you only want reviews from people.

Each review has these properties:

<table><thead><tr><th width="153.31640625">Property</th><th>Description</th></tr></thead><tbody><tr><td>Bot generated</td><td>Whether a bot account left the review. Written as <code>botGenerated</code> in CQL.</td></tr><tr><td>Organization</td><td>The GitHub organization that owns the repository.</td></tr><tr><td>Repository</td><td>The repository containing the pull request that was reviewed.</td></tr><tr><td>Review date</td><td>When the review was left.</td></tr><tr><td>Reviewer</td><td>The GitHub user account or bot account that left the review.</td></tr></tbody></table>

**Definition** - `git.reviews(lookback: Duration)`

**Example**

A development maturity Scorecard might use the `git.reviews()` expression to make sure that a rigorous review process is in place before changes are implemented:

```
git.reviews(lookback=duration("P7D")).length > 25
```

This rule makes sure that more than 25 reviews were left in the last week.

**Example**

Because bot reviews count toward that total, filter them out to hold the threshold to reviews left by people:

```
git.reviews(lookback=duration("P7D")).filter((review) => !review.botGenerated).length > 25
```

Reverse the filter to `review.botGenerated` to measure automated review activity on its own.

</details>

<details>

<summary>Workflow runs</summary>

Get workflow runs meeting given filter criteria, including conclusions, statuses, and a lookback period.

* Conclusion
* Name
* Run started at
* Run time
* Run updated at
* Status

Conclusions: `FAILURE`, `SUCCESS`, `TIMED_OUT`

Statuses: `QUEUED`, `IN_PROGRESS`, `COMPLETED`

The lookback period specifies a duration for which returned runs should be created within, defaulting to a period of 3 days.

* The `runTime` of the `WorkflowRun` object represents the difference between `runStartedAt` and `runUpdatedAt` times in seconds.

**Definition:** `git.workflowRuns()`

**Example**

To make sure an entity has had a successful workflow run within the last two weeks, you can write a rule like:

```
git.workflowRuns(conclusions=["SUCCESS"], statuses=["COMPLETED"], lookback=duration("P14D")).length > 0
```

This rule is checking for GitHub workflow runs with a `SUCCESS` conclusion and `COMPLETED` status during a 14-day lookback window.\\

To find the percentage of successes in workflow runs, you could write a query similar to:

```
(git.workflowRuns(conclusions=["SUCCESS"], lookback=duration("P1D")).length) / (git.workflowRuns(lookback=duration("P1D")).length) * 100
```

</details>

**Ownership CQL**

<details>

<summary>All ownership details</summary>

A special built-in type that supports a null check or a count check, used to enforce ownership of entities.

**Definition:** `ownership: Ownership | Null`

**Example**

An initial level in a security Scorecard might include a rule to ensure an entity has at least one team as an owner:

```
ownership.teams().length > 0
```

</details>

<details>

<summary>All owner details</summary>

List of owners, including team members and individual users, for each entity

**Definition:** `ownership.allOwners()`

**Example**

The Scorecard might include a rule to ensure that entity owners all have an email set:

```
ownership.allOwners().all((member) => member.email != null)
```

</details>

<details>

<summary>Team details</summary>

List of teams for each entity

**Definition:** `ownership.teams(): List<Team>`

**Example**

The Scorecard might include a rule to ensure that an entity owners all have a description and are not archived:

```
ownership.teams().all(team => team.description != null and team.isArchived == false)
```

</details>

**Copilot CQL**

<details>

<summary>AI adoption</summary>

The ratio of licensed seats that were active users of AI coding tools in a given time period. Returns a value between 0 and 1, where 1 represents 100% adoption. Note: This metric is only available for Team entities.

**Definition**: `aiTools.analysis(lookback: Duration).aiAdoptionRate`

**Example**

You could create a Scorecard rule to make sure AI adoption rate is at least 50% over the previous 30 days:

```
aiTools.analysis(lookback = duration("P30D")).aiAdoptionRate >= 0.5
```

</details>

<details>

<summary>Active AI users</summary>

The number of users who used AI coding tools in a given time period. Note: This metric is only available for Team entities.

**Definition**: `aiTools.analysis(lookback: Duration).activeAiUsers`

**Example**

You could create a Scorecard rule to verify you had at least 5 active AI users in the last 7 days:

```
aiTools.analysis(lookback = duration("P7D")).activeAiUsers >= 5
```

</details>

**External repositories**

By default, each GitHub rule is evaluated on the repository defined in a given entity descriptor. If the base path parameter has been set, CQL rules will automatically scope to the base path subdirectory.

To evaluate the rule for a service for an external repository, pass the repo identifier in the `git(repoIdentifier: Text)` command (e.g. `git("github:org/repositoryName")`).

This can be combined with other CQL rules. For example, a rule based on a dynamic external repository with custom data would be `git("github:" + custom("my-custom-repo")).fileExists("README.md")`.

### View integration logs <a href="#still-need-help" id="still-need-help"></a>

{% hint style="info" %}
This feature is available in Cortex cloud.
{% endhint %}

While viewing an integration's settings page, select the **Logs** tab to view error logs from the last 7 days. You can filter the logs list by configuration and by operation (for example, you could filter to view errors surfaced only via Scorecards).

<div align="left" data-with-frame="true"><figure><img src="/files/x8JmoPqXZTJ7YHeFJpOA" alt="The &#x27;Logs&#x27; tab on an integration&#x27;s settings page shows error information over the past 7 days."><figcaption></figcaption></figure></div>

Click into a row to get more information, including time stamp, status code, full error, and request path.

## Background sync

Cortex syncs GitHub identities (teams and people) once a day, at 9 a.m. UTC.

Repository and pull request syncs start within 10 minutes of the previous sync's completion. In most cases, this means Cortex's GitHub data is no more than 10 minutes old, though a sync that takes longer than usual can push that slightly further out.

## FAQs and troubleshooting

**I'm getting this error: `"{"message":"Not Found", "documentation_url":"https://docs.github.com/rest/repos#get-a-repository"}"`.**

If you've set up multiple GitHub accounts/organizations, Cortex will not be able to identify the correct one unless the `alias` variable is defined.

**What if I have multiple email addresses set in my GitHub account?**

Cortex will only detect the primary email address associated with your GitHub account **if it is public**.

If Cortex is not correctly pulling in user emails, ensure the given user(s) have allowed their email address to be public. Make sure the **"Keep my email address private"** setting is **unchecked** in the user's personal GitHub settings.

**My ownership isn't being automatically mapped through GitHub.**

If the email address associated with your Cortex account is not the same as your GitHub email address, you need to add your Cortex email address to the **Public email** dropdown in GitHub settings.

Github OAuth, which you can configure in Cortex user settings, allows you to link your GitHub username with your Cortex account, even if you don't have a public email set up on GitHub.

## Still need help?[​](https://docs.cortex.io/docs/reference/integrations/aws#still-need-help) <a href="#still-need-help" id="still-need-help"></a>

The following options are available to get assistance from the Cortex Customer Engineering team:

* **Email**: <help@cortex.io>, or open a support ticket in the in app Resource Center
* **Slack**: Users with a connected Slack channel will have a workflow added to their account. From here, you can either @CortexTechnicalSupport or add a `:ticket:` reaction to a question in Slack, and the team will respond directly.

Don’t have a Slack channel? Talk with your Customer Success Manager.


# GitLab

{% hint style="info" %}
Cortex connects to many third-party vendors whose system interfaces frequently change. As a result, integration behavior or configuration steps may shift without notice. If you encounter unexpected issues, check with your system administrator or refer to the vendor's documentation for the most current information. Additionally, integration sync times vary and are subject to scheduling overrides and timing variance.
{% endhint %}

[GitLab](https://about.gitlab.com/) is a Git-based version control system with cloud and self-hosted options.

Integrating GitLab with Cortex allows you to:

* Discover and track ownership of entities
* Follow a [GitOps](/configure/gitops) workflow with GitLab
* View commits alongside events and other data on [entity pages in Cortex](#view-gitlab-data-on-entity-pages-in-cortex)
* View information about merge requests in the [engineering homepage](#engineering-homepage)
* Use GitLab metrics in [Eng Intelligence](#eng-intelligence) to understand key metrics and gain insight into services, incident response, and more
* Create [Scorecards](#scorecards-and-cql) to monitor development maturity relating to GitLab projects

## How to configure GitLab with Cortex

There are two options for integrating GitLab: the default configuration method and Cortex Axon Relay, a relay broker allows you to securely connect your on-premises GitLab data.

### Prerequisites

Before getting started:

* A GitLab user with at least the `Maintainer` role must create a GitLab [personal access token](https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html) or [group access token](https://docs.gitlab.com/ee/user/group/settings/group_access_tokens.html) with the `read_api` scope.
  * We recommend that you create the token at the parent group level, as GitLab does not support using a scoped token to read members from a parent group. If you do not create the token at the parent level, then you will need to manually configure groups in your GitLab settings in order for identity mapping and teams to work as expected.
  * Note that `Maintainer` is sufficient for project/repo data, but retrieving user emails for identity mapping typically requires an `Owner`- or `Admin`-generated token with `api` or `read_user` scope, particularly in enterprise/SSO environments.
* If you're using the Scaffolder for entities in a given GitLab instance, make sure that configuration has the full `api` scope.

#### Self-hosted prerequisites

If you're using a self-hosted instance of GitLab, you'll need to verify that your Cortex instance is able to reach the GitLab instance.\
\
We route our requests through a static IP address. Reach out to support at <help@cortex.io> to receive details about our static IP. If you're unable to directly allowlist our static IP, you can route requests through a secondary proxy in your network that has this IP allowlisted and have that proxy route traffic to your GitLab instance.

{% tabs %}
{% tab title="Standard configuration" %}
**Configure the integration in Cortex**

1. In Cortex, navigate to the [GitLab settings page](https://app.getcortexapp.com/admin/integrations/gitlab):
   * Click **Integrations** from the main nav. Search for and select **GitLab**.
2. Click **Add configuration**.
3. Configure the GitLab integration form:
   * **Account alias**: Enter the alias you will use to tie entity registrations to different configuration accounts.
   * **Token**: Enter your personal or group access token.
   * **Host**: Enter your host. If using a custom GitLab instance, enter the URL without the API path (e.g. `https://gitlab.getcortexapp.com`)
   * **Hide personal projects**: Toggle this setting on if you do not want your personal projects pulled in to Cortex. Toggle this setting off to allow Cortex to pull your personal projects.
4. Click **Save**.
   {% endtab %}

{% tab title="Relay broker" %}
**Configure GitLab with Cortex Axon Relay**

See [Internally hosted integrations](/ingesting-data-into-cortex/integrations/axon-relay) for instructions. Make sure to follow the GitLab-specific instructions for the docker-compose.yml file.
{% endtab %}
{% endtabs %}

Once you save your configuration, you'll see it listed on the integration's settings page in Cortex. If you’ve set everything up correctly, you’ll see the option to **Remove Integration** in Settings.

You can also use the **Test all configurations** button to confirm that the configuration was successful. If your configuration is valid, you’ll see a banner that says “Configuration is valid. If you see issues, please see documentation or reach out to Cortex support.”

**Configure the integration for multiple GitLab accounts**[**​**](https://docs.cortex.io/docs/reference/integrations/gitlab#configure-the-integration-for-multiple-propsintegration-accounts)

The GitLab integration has multi-account support. You can add a configuration for each additional by repeating the process above.

Each configuration requires an alias, which Cortex uses to correlate the designated with registrations for various entities. Registrations can also use a default configuration without a listed alias. You can edit aliases and default configurations from the GitLab page in your Cortex settings. Select the edit icon next to a given configuration and toggle **Set as default** on. If you only have one configuration, it will automatically be set as the default.

Cortex supports mapping multiple identities for a single user if you have multiple configurations of GitLab. See the [Identity mapping documentation](/configure/settings/managing-users/identity-mapping) for more information.

## Enable GitOps for your GitLab integration

Cortex supports a GitOps approach, which allows you to manage entities in Cortex through your version control system. If you would prefer this workflow over the UI for the GitLab integration, you must create a webhook. Please see the [Cortex GitOps documentation](/configure/gitops) for instructions.

## How to connect Cortex entities to GitLab

### Import entities

Cortex will discover entities for import from your GitLab configuration(s). These will appear in the import entities workflow.

See the [Create services documentation](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/add-services#creating-services) for instructions on importing entities manually.

### Editing the entity descriptor

**Git**

By specifying the `x-cortex-git` field in your Cortex entity descriptor, you'll be able to see Git information in the entity page, including the top language, recent commits, and top contributors.

```yaml
x-cortex-git:
  gitlab:
    repository: cortex/docs
    basepath: myService
    alias: myApp
```

| Field        | Description                                                                                      | Required |
| ------------ | ------------------------------------------------------------------------------------------------ | :------: |
| `repository` | GitLab project ID or `namespace/repo` as defined in GitLab                                       |   **✓**  |
| `basepath`   | Subdirectory for the entity if it is in a monorepo                                               |          |
| `alias`      | Alias for the configuration in Cortex (only needed if you have opted into multi-account support) |          |

Only one repository can be defined for in a given entity's YAML in the `x-cortex-git` block.

**Ownership**

You can define the following block in your Cortex entity descriptor to add your GitLab groups.

Team name should match the group name in GitLab.

```yaml
x-cortex-owners:
  - type: group
    name: Team Name
    provider: GITLAB
    description: This is a description for this owner
```

| Field         | Description                                                 | Required |
| ------------- | ----------------------------------------------------------- | :------: |
| `type`        | Ownership type; must be defined as `group` for GitLab teams |   **✓**  |
| `name`        | GitLab team name                                            |   **✓**  |
| `provider`    | Name of integration (in this case, `GITLAB`)                |   **✓**  |
| `description` | Description for the GitLab team                             |          |

### Identity mapping

Cortex maps users' email addresses to discovered GitLab accounts, so you never need to define email ownership in an entity descriptor.

You can confirm users' GitLab accounts are connected from [GitLab identity mappings in settings](https://app.getcortexapp.com/admin/settings/gitlab-mappings).

If users are not loading in the identity mapping page, make sure that you have created your GitLab personal access token from the parent level as described in the [Prerequisites](#prerequisites).

## Using the GitLab integration

### View GitLab data on entity pages in Cortex

Cortex uses the GitLab integration for a significant amount of data that appears on [entities' detail pages](/ingesting-data-into-cortex/entities-overview/entities/details).

The GitLab integration will populate the **Repo** and **Language** detail blocks on an entity's details page.

In the **Recent activity preview**, you'll find the recent commits and releases. These will also appear in the event timeline.

These data will appear for entities imported from a Git source or those that have a Git repo defined in their YAMLs.

#### **Events**

On an entity's **Events** page, you can find all of the commits and releases associated with that entity. Each is hyperlinked to the commit or release page in GitLab and includes a timestamp.

#### **CI/CD**

To see pipeline runs for GitLab, use the [deploys API](/ingesting-data-into-cortex/entities-overview/entities/deploys) to add deploy information. After doing this, from the **CI/CD > Deploys** page in the entity's sidebar, you will see a history of pipeline runs.

#### **Repository**

You can access more detailed information pulled from GitLab in the **Repository** page in the entity's sidebar. At the top of the page, you'll find the repo associated with that entity and the most-used language in files for that entity. In the **Top contributors** block, you'll find the three users who have contributed the most code and the number of their contributions.

In the Commits section, you'll find the 10 most recent commits and metadata about each. Below Commits is the Recent releases section, which includes the 5 most recent releases.

#### **Packages**

Packages are automatically scraped from your Git repos or they can be submitted via the [packages API](/api/readme/packages). The package file must be in the root of your repository — or, if you're using `basepath`, in the root of the subdirectory — to be scraped by Cortex. You can query an entity's packages in [CQL explorer](https://app.getcortexapp.com/admin/cql-explorer) using `packages()`.

To view packages, click **Packages** in the entity's sidebar.

The following package types are automatically scraped from repositories:

* JavaScript / Node.js: `package.json`, `package-lock.json`, `yarn.lock`, `pnpm-lock.yaml`
* Python: `requirements.txt`, `pipfile.lock`
* .NET (C#): `packages.lock.json`
* Java: `pom.xml`
* Go: `go.sum`

All other files of these types can be added via the [packages API](/api/readme/packages).

#### Team pages

When a GitLab team is registered in a team entity descriptor, Cortex will pull GitLab users in to the **Members** tab. When available, Cortex will pull in the profile picture and email address for each user.

If team members are not appearing as expected, make sure that you have created your GitLab personal access token from the parent level as described in the [Prerequisites](#prerequisites).

### Engineering homepage

The GitLab integration enables Cortex to pull information about merge requests into the [homepage](/streamline/homepage). You can find your open merge requests and any merge requests assigned to you for review.

Merge requests from GitLab are refreshed every 2 minutes.

### Eng Intelligence

The [Eng Intelligence tool](/improve/eng-intelligence) also uses merge request data from GitLab to generate metrics:

* Average MR open to close time
* Avg time to first review
* Avg time to approval
* MRs opened
* Weekly MRs merged
* Avg MRs reviewed/week
* Avg commits per MR
* Avg lines of code changed per MR

You can read more about how Eng Intelligence tracks metrics for teams and users in the Eng Intelligence walkthrough.

To add deployments for your GitLab related entity, you can send a deployment event to the [Cortex API](/api/readme/deploys).

### Scorecards and CQL

With the GitLab integration, you can create Scorecard rules and write CQL queries based on GitLab data.

See more examples in the [CQL Explorer](https://app.getcortexapp.com/admin/cql-explorer) in Cortex.

<details>

<summary>Approvals required to merge</summary>

Number of approvals required to merge a pull/merge request into a repository. Defaults to 0 if no approvals are defined.

**Definition**: `git.numOfRequiredApprovals()`

**Examples**

For a security or development maturity Scorecard, you can write a rule to make sure at least one approval is required to merge a pull/merge request:

```
git.numOfRequiredApprovals() > 0
```

By having a rigorous PR process in place for a repo, you can make sure changes aren't made that create vulnerabilities. This kind of rule could also be used in a best practices or project standards Scorecard.

You can also use a similar expression in the Query Builder to find entities lacking approval:

```
git.numOfRequiredApprovals() < 1
```

</details>

<details>

<summary>Git repository set</summary>

Check if an entity has a registered Git repository.

**Definition:** `git (==/!=) null: Boolean`

**Example**

In a Scorecard, you can write a rule that detects whether an entity has a Git repository set:

```
git != null
```

</details>

<details>

<summary>Pipeline build success rate</summary>

The percentage of build pipelines that complete successfully. This is calculated against builds on the default branch, for commits in the last 30 days. The calculation is # successful builds / (# successful + # failed).

**Definition:** `git.percentBuildSuccess(): Number`

**Example**

In a Scorecard, you can write a rule that requires at least 90% of build runs to be successful:

```
git.percentBuildSuccess() > 0.9
```

</details>

<details>

<summary>Branches</summary>

List all live branches with some basic metadata.

* Head
* Is protected
* Name

**Definition**: `git.branches()`

**Example**

For a best practices Scorecard, you can make sure that branches associated with an entity match a standard naming convention:

```
git.branches().all((branch) => branch.name.matches("(main|master|feat-.*|bug-.*|task-.*)"))
```

</details>

<details>

<summary>Branch protection details</summary>

Find details for specified branch, or default branch if none is specified.

* Branch name
* Code owner reviews required
* Dismiss stale reviews
* Required status checks
* Restrictions apply to admin
* Review required

**Definition:** `git.branchProtection()`

**Examples**

For a security Scorecard, you can write a rule to make sure the default branch is protected:

```
git.branchProtection() != null
```

Because vulnerabilities in the default branch are critical, this rule should be in one of the first couple levels.

You can also use the Query Builder to find entities with unprotected default branches:

```
git.branchProtection() = null
```

</details>

<details>

<summary>Commits</summary>

Get the latest commits **(to a maximum of 100)** for a defined lookback period **(defaulting to 7 days)**.

* Date
* Message
* SHA
* URL
* Username

These results can be filtered based on branch name, using the default branch if no other branch is provided.

**Definition:** `git.commits()`

**Example**

You can use the `git.commits()` expression in a security Scorecard to make sure entities have fewer than three commits to a "security-fixes" branch in the last week:

```
git.commits(branch="security-fixes", lookback=duration("P7D")).length < 3
```

Entities passing this rule will include those that haven't needed three or more security fixes. This can indicate that there aren't vulnerabilities in a given entity's code, but could also suggest that fixes aren't being implemented. Using this rule in conjunction with one focused on vulnerabilities could provide the extra context needed to gain a better understanding of what's happening.

</details>

<details>

<summary>Default branch</summary>

Default branch for the repository, or `main` when null.

**Definition:** `git.defaultBranch()`

**Example**

If default branches should always be named "main," you can write a rule to make sure entities follow this practice:

```
git.defaultBranch().matches("main")
```

</details>

<details>

<summary>File contents</summary>

Load the contents of a file from the entity's associated repository.

The contents can be validated by using string comparison operations or parsed by the built-in jq function. The jq function will automatically coerce file contents of JSON or YAML formats.

**Definition:** `git.fileContents()`

**Example**

For a Scorecard focused on development maturity, you could use the `git.fileContents()` rule to enforce that a CI pipeline exists, and that there is a testing step defined in the pipeline.

```
git.fileContents("circleci/config.yml").matches(".*npm test.*")
```

A best practices Scorecard, meanwhile, could use this expression for a number of rules:

* To make sure node engine version in specified in the `package.json` file:

  ```
  jq(git.fileContents("package.json"), ".engines.node") != null
  ```
* To make sure TypeScript projects have a `tsconfig.json` file checked in:

  ```
  jq(git.fileContents("package.json"), ".devDependencies | with_entries(select(.key == \"typescript\")) | length") == 0 or git.fileExists("tsconfig.json")
  ```
* To make sure projects using yarn do not allow NPM:

  ```
  jq(git.fileContents("package.json"), ".engines.yarn") == null or jq(git.fileContents("package.json"), ".engine.npm") = "please-use-yarn"
  ```
* And to ensure the yarn version being used is not deprecated:

  ```
  jq(git.fileContents("package.json"), ".engines.yarn") == null or !(semver("1.2.0") ~= semverRange(jq(git.fileContents("package.json"), ".engines.yarn")))
  ```

</details>

<details>

<summary>File exists</summary>

Check if file exists from within the entity's associated repository.

**Definition:** `git.fileExists()`

**Examples**

For a Scorecard focused on best practices, you can make sure that repositories contain a README.md file:

```
git.fileExists("README.md")
```

This rule would make sense in the first level because it's so essential.

A higher-level rule in a best practices Scorecard might confirm that developers are checking in lockfiles to ensure consistency in package installs:

```
git.fileExists("yarn.lock") OR git.fileExists("package-lock.json")
```

And/or a rule that makes sure there are unit tests enabled:

```
git.fileExists("*Test.java")
```

Finally, you could write a rule to make sure projects have a standard linter:

```
git.fileExists(".prettierrc.json") OR git.fileExists(".eslintrc.js")
```

</details>

<details>

<summary>Number of Git vulnerabilities</summary>

Check the number of vulnerabilities for an entity's associated repository.

**Definition:** `git.numOfVulnerabilities()`

**Examples**

A security-focused Scorecard will likely include a rule making sure there are no Git vulnerabilities:

```
git.numOfVulnerabilities() == 0
```

You can use Scorecard levels to stratify vulnerabilities by risk. An initial level might make sure there are no critical vulnerabilities:

```
git.numOfVulnerabilities(severity=["CRITICAL"]) == 0
```

While a higher level might make sure there are no vulnerability warnings:

```
git.numOfVulnerabilities(severity=["WARNING"]) == 0
```

</details>

<details>

<summary>List of Git vulnerabilities</summary>

Find all vulnerabilities within a repository. Can filter by severity or scan type.

**Definition**: `git.vulnerabilities()`

**Examples**

You could write a Scorecard rule that verifies an entity has fewer than 5 Git vulnerabilities:

```
git.vulnerabilities().length < 5
```

You could write a rule to verify that an entity has no critical vulnerabilities:

```
git.vulnerabilities(severity=["CRITICAL"]).length == 0
```

</details>

<details>

<summary>Has Cortex YAML</summary>

Check if a repository has a valid `cortex.yaml` file checked in at the root directory (when GitOps is enabled).

**Definition:** `git.hasCortexYaml()`

**Example**

If you're using a Scorecard to track a migration from Cortex UI to GitOps, you can use this rule to make sure entities are set up for GitOps management of entity descriptors:

```
git.hasCortexYaml() == true
```

</details>

<details>

<summary>Last commit details</summary>

Provides last commit details.

* Date
* Message
* SHA
* URL
* Username

**Definition:** `git.lastCommit()`

**Examples**

One of the first rules you might write for a Scorecard focused on development maturity or security is one validating that the last commit was within the last month:

```
git.lastCommit().freshness < duration("P1M")
```

As counterintuitive as it may seem, services that are committed too infrequently are actually at more risk. People who are familiar with the service may leave a team, institutional knowledge accumulates, and from a technical standpoint, the service may be running outdated versions of your platform tooling.

Depending on best practices at your organization, you may want to confirm entities are updated within a week:

```
git.lastCommit().freshness < duration("P7D")
```

Confirming whether a service was updated within the last week can help team members catch outdated code sooner. Plus, if there is a security issue, you can quickly determine which services have or have not been updated to patch the vulnerability.

</details>

<details>

<summary>Pull requests</summary>

Lists pull requests opened during a defined lookback period.

* Approval date
* Author
* Date closed
* Date opened
* First review date
* Is draft
* Last updated
* Number of commits
* Number of lines added
* Number of lines deleted
* Organization
* Repository
* Source
* Status
* URL

**Definition:** `git.pullRequests()`

**Example**

You can use the `git.pullRequests()` query to find entities that have a small number of pull requests opened in the last two weeks:

```
git.pullRequests(lookback=duration("P14D")).length < 3
```

This can highlight entities that haven't been updated recently, which may be especially useful when entities have to be updated to address a vulnerability.

**Example**

You can filter out draft pull requests to count only ready-for-review PRs:

```
git.pullRequests(lookback=duration("P14D")).filter(pr => !pr.isDraft).length < 3
```

</details>

<details>

<summary>Reviews</summary>

List reviews left during a defined lookback period.

* Organization
* Repository
* Review date
* Reviewer

**Definition:** `git.reviews()`

**Examples**

A development maturity Scorecard might use the `git.reviews()` expression to make sure that there is a rigorous review process in place before changes are implemented:

```
git.reviews(lookback=duration("P7D")).length > 25
```

This rule makes sure that there are more than 25 reviews left in the last week.

</details>

<details>

<summary>Workflow runs</summary>

Get workflow runs meeting given filter criteria, including conclusions, statuses, and a lookback period.

* Conclusion
* Name
* Run started at
* Run time
* Run updated at
* Status

Conclusions: `FAILURE`, `SUCCESS`, `TIMED_OUT`

Statuses: `QUEUED`, `IN_PROGRESS`, `COMPLETED`

The lookback period specifies a duration for which returned runs should be created within, defaulting to a period of 3 days.

* The `runTime` of the `WorkflowRun` object represents the difference between `runStartedAt` and `runUpdatedAt` times in seconds.

**Definition:** `git.workflowRuns()`

**Example**

To make sure an entity has had a successful workflow run within the last two weeks, you can write a rule like:

```
git.workflowRuns(conclusions=["SUCCESS"], statuses=["COMPLETED"], lookback=duration("P14D")).length > 0
```

This rule is checking for GitHub workflow runs with a `SUCCESS` conclusion and `COMPLETED` status during a 14-day lookback window.

</details>

**Ownership CQL**

<details>

<summary>All ownership details</summary>

A special built-in type that supports a null check or a count check, used to enforce ownership of entities.

**Definition:** `ownership: Ownership | Null`

**Example**

An initial level in a security Scorecard might include a rule to ensure an entity has at least one team as an owner:

```
ownership.teams().length > 0
```

</details>

<details>

<summary>All owner details</summary>

List of owners, including team members and individual users, for each entity

**Definition:** `ownership.allOwners()`

**Example**

The Scorecard might include a rule to ensure that entity owners all have an email set:

```
ownership.allOwners().all((member) => member.email != null)
```

</details>

<details>

<summary>Team details</summary>

List of teams for each entity

**Definition:** `ownership.teams(): List<Team>`

**Example**

The Scorecard might include a rule to ensure that an entity owners all have a description and are not archived:

```
ownership.teams().all(team => team.description != null and team.isArchived == false)
```

</details>

### View integration logs <a href="#still-need-help" id="still-need-help"></a>

{% hint style="info" %}
This feature is available in Cortex cloud.
{% endhint %}

While viewing an integration's settings page, select the **Logs** tab to view error logs from the last 7 days. You can filter the logs list by configuration and by operation (for example, you could filter to view errors surfaced only via Scorecards).

<div align="left" data-with-frame="true"><figure><img src="/files/x8JmoPqXZTJ7YHeFJpOA" alt="The &#x27;Logs&#x27; tab on an integration&#x27;s settings page shows error information over the past 7 days."><figcaption></figcaption></figure></div>

Click into a row to get more information, including time stamp, status code, full error, and request path.

## Background sync

Cortex conducts a background sync of GitLab identities every day at 10 a.m. UTC. Merge requests are refreshed every 2 minutes.

## FAQ and Troubleshooting

**Why is my CQL query `git.branchProtection()` returning no results or a 403 error?**

This can happen if you do not have the `read_api` scope set for your access token, or if the GitLab user who generated the token does not have at minimum the `Maintainer` role.

**Why isn't Cortex pulling in user emails from GitLab (identity mapping / team members missing emails)?**

Email addresses are treated as sensitive user identity data in GitLab, not project data, so a `Maintainer`-level token isn't sufficient in most modern GitLab environments, especially enterprise instances with SSO or stricter privacy controls. Use a token created by an `Owner` or `Admin` user with the `api` (or `read_user`) scope.

Note that `Maintainer` tokens *may* work on loosely configured self-managed instances, but this is not reliable. Email visibility also depends on instance configuration and individual user privacy settings (e.g., hidden emails).

## Still need help?[​](https://docs.cortex.io/docs/reference/integrations/aws#still-need-help) <a href="#still-need-help" id="still-need-help"></a>

The following options are available to get assistance from the Cortex Customer Engineering team:

* **Email**: <help@cortex.io>, or open a support ticket in the in app Resource Center
* **Slack**: Users with a connected Slack channel will have a workflow added to their account. From here, you can either @CortexTechnicalSupport or add a `:ticket:` reaction to a question in Slack, and the team will respond directly.

Don’t have a Slack channel? Talk with your Customer Success Manager.


# Google Cloud Platform

Configuring the integration for Google Cloud Platform (GCP)

{% hint style="info" %}
Cortex connects to many third-party vendors whose system interfaces frequently change. As a result, integration behavior or configuration steps may shift without notice. If you encounter unexpected issues, check with your system administrator or refer to the vendor's documentation for the most current information. Additionally, integration sync times vary and are subject to scheduling overrides and timing variance.
{% endhint %}

## Why use the integration for Google Cloud Platform

Google Cloud Platform (GCP) is Google's suite of cloud computing services, including compute, storage, data, and AI/ML products. Integrating Cortex with GCP gives you automatic visibility into your cloud infrastructure and how it connects to the rest of your catalog.

This integration works alongside Cortex's broader Google integration, which also connects to Google Workspace to sync ownership from Google Groups. Together, they help Cortex build a live picture of your cloud footprint and who owns it.

With the GCP integration, Cortex can:

* Automatically discover GCP entities, like Cloud Run services, BigQuery datasets, and Kubernetes Engine clusters, and add them to your catalog.
* Link those entities to the services that depend on them, using tags Cortex matches automatically or dependencies you define explicitly.
* Pull in Service Level Objectives (SLOs) from Google Cloud Observability and surface them on entity pages.
* Power Scorecards and CQL queries that check GCP configuration, SLO health, and ownership across your catalog.

Cortex connects to GCP through a service account with read-only permissions scoped to the entity types you want to sync. Cortex only reads from GCP; it doesn't make changes to your cloud resources.

{% hint style="info" %}
For information on configuring Google SSO for logging in to Cortex, see the [Google SSO documentation](/configure/settings/managing-users/configuring-sso).
{% endhint %}

## Supported Google Cloud entity types

Cortex supports importing the following entity types from Google Cloud:

<details>

<summary>Supported Google Cloud entity types</summary>

* Google Cloud Vertex AI Batch Prediction Job
* Google Cloud Vertex AI Dataset
* Google Cloud Vertex AI Endpoint
* Google Cloud Vertex AI Featurestore
* Google Cloud Vertex AI Index
* Google Cloud Vertex AI Model
* Google Cloud Vertex AI Model Deployment Monitoring Job
* Google Cloud Vertex AI Notebooks Instance
* Google Cloud Vertex AI Pipeline Job
* Google Cloud Vertex AI Platform Index Endpoint
* Google Cloud Vertex AI Specialist Pool
* Google Cloud Vertex AI Study
* Google Cloud Vertex AI Tensorboard
* Google Cloud Vertex AI Training Pipeline
* Google Cloud Vertex AI Vision Application
* Google Cloud Vertex AI Vision Cluster
* Google Cloud Vertex AI Vision Index Point
* Google Cloud Vertex AI Vision Operator
* Google Cloud Vertex AI Vision Processor
* Google Cloud Apigee Api
* Google Cloud Apigee Instance
* Google Cloud App Engine Service
* Google Cloud Artifact Registry Repository
* Google Cloud BigQuery Connection
* Google Cloud BigQuery
* Google Cloud Composer Environment
* Google Cloud Functions
* Google Cloud Kubernetes Engine Clusters
* Google Cloud Kubernetes Engine Operations
* Google Cloud IAM Service Account
* Google Cloud Instance Group
* Google Cloud HTTP(S) Load Balancing
* Google Cloud Memorystore Memcached
* Google Cloud Memorystore Redis
* Google Cloud Project
* Google Cloud Run Job
* Google Cloud Run Service
* Google Cloud Spanner Instance
* Google Cloud Spanner Instance Config
* Google Cloud SQL
* Google Cloud Storage
* Google Cloud Pub/Sub Topics
* Google Cloud VM Instances
* Google Cloud VPC Serverless Connector

</details>

## Configuring Google Cloud Platform

### Prerequisites

1. Users with the `Configure Integrations` permission can configure GCP.
2. A [Google service account](https://docs.cloud.google.com/iam/docs/service-account-overview) and its client ID.
   * In the Advanced settings, enable **Domain-wide Delegation**.
   * Under Domain-wide Delegation, copy the client ID and store it in a secure location. Do not skip this step! You'll need the client ID to complete setup.
   * The service account must include permissions for each project to enable Google Cloud resources. See [Google service account permissions](#google-service-account-permissions) below.
3. The [Google Admin SDK API](https://console.developers.google.com/apis/api/admin.googleapis.com/overview) is configured and enabled.&#x20;
4. Google Cloud resource project permissions are enabled for each project. See [Google Cloud resource project permissions](#google-cloud-resource-project-permissions) below.

#### Google service account permissions

<details>

<summary>Expand to view the list of Google service account permissions</summary>

* AI Platform → AI Platform Viewer, Dataform Viewer, Cloud Storage for Firebase Viewer, Data Catalog Viewer, Vision AI Viewer, Notebooks Viewer, Dataflow Viewer
* Apigee → Cloud Api Hub Viewer
* App Engine → App Engine Viewer
* Artifact Registry → Artifact Registry Reader
* BigQuery → BigQuery Metadata Viewer
* BigQuery Connection → BigQuery Connection User
* Cloud Asset → Cloud Asset Viewer
* Cloud Asset → ListResource
  * Note: This permission is necessary to run services and jobs.
* Cloud Functions → Cloud Functions Viewer
* Cloud Pub/Sub → Pub/Sub Viewer
* Cloud Resource Manager → Browser
* Cloud Run → Cloud Run Viewer
* Cloud SQL → Cloud SQL Viewer
* Cloud Storage → Storage Admin
* Composer → Composer User
* Compute Engine, VM Instances → Compute Viewer
* Kubernetes Engine → Kubernetes Engine Viewer
* Memorystore Memcached → Cloud Memorystore Memcached Viewer
* Memorystore Redis → Cloud Memorystore Redis Viewer
* Monitoring → Monitoring Viewer
* Service Accounts → View Service Accounts
* Spanner → Cloud Spanner Viewer
* VM Instances Vulnerabilities → OS VulnerabilityReport Viewer
* VPC Serverless Connector → Serverless VPC Access Viewer

</details>

To create a custom role with only the minimum required permissions, add the following:

<details>

<summary>Expand to view the list of custom role minimum permissions</summary>

```
aiplatform.datasets.get
aiplatform.datasets.list

aiplatform.endpoints.get
aiplatform.endpoints.list

aiplatform.featurestores.get
aiplatform.featurestores.list

aiplatform.indexEndpoints.get
aiplatform.indexEndpoints.list

aiplatform.batchPredictionJobs.get
aiplatform.batchPredictionJobs.list

aiplatform.modelDeploymentMonitoringJobs.get
aiplatform.modelDeploymentMonitoringJobs.list

aiplatform.trainingPipelines.get
aiplatform.trainingPipelines.list

aiplatform.pipelineJobs.get
aiplatform.pipelineJobs.list

aiplatform.specialistPools.get
aiplatform.specialistPools.list

aiplatform.tensorboardExperiments.get
aiplatform.tensorboardExperiments.list

aiplatform.studies.get
aiplatform.studies.list

aiplatform.apps.get
aiplatform.apps.list

aiplatform.indexes.get
aiplatform.indexes.list

aiplatform.models.get
aiplatform.models.list

aiplatform.tensorboards.get
aiplatform.tensorboards.list

iam.serviceAccounts.get

apihub.apiHubInstances.get

apihub.apis.get
apihub.apis.list

appengine.services.get
appengine.services.list

artifactregistry.repositories.get
artifactregistry.repositories.list

bigquery.connections.get
bigquery.connections.list

bigquery.datasets.get
bigquery.routines.get
bigquery.routines.list

cloudasset.assets.listResource

cloudfunctions.functions.get
cloudfunctions.functions.list

cloudsql.instances.get
cloudsql.instances.list

composer.environments.get
composer.environments.list

compute.urlMaps.list
compute.urlMaps.get
compute.instances.list
compute.instances.get
compute.instanceGroups.list
compute.instanceGroups.get

container.clusters.get
container.clusters.list

container.operations.get
container.operations.list

iam.serviceAccounts.get
iam.serviceAccounts.list

memcache.instances.list
memcache.instances.get

monitoring.services.get
monitoring.services.list
monitoring.slos.get
monitoring.slos.list
monitoring.timeSeries.list

notebooks.instances.get
notebooks.instances.list

osconfig.vulnerabilityReports.get

pubsub.topics.get
pubsub.topics.list

redis.instances.list
redis.instances.get

resourcemanager.projects.get
resourcemanager.projects.list

run.jobs.list
run.jobs.get

run.services.list
run.services.get

spanner.instances.get
spanner.instances.list

spanner.instanceConfigs.get
spanner.instanceConfigs.list

storage.buckets.get
storage.buckets.list

visionai.applications.get
visionai.applications.list

visionai.processors.get
visionai.processors.list

visionai.operators.get
visionai.operators.list

visionai.clusters.get
visionai.clusters.list

vpcaccess.connectors.get
vpcaccess.connectors.list

```

</details>

#### Google Cloud resource project permissions

<details>

<summary>Expand to view the list of Google Cloud resources project permissions</summary>

* [App Engine Admin API](https://console.cloud.google.com/marketplace/product/google/appengine.googleapis.com)
* [ArtifactRegistry API](https://console.cloud.google.com/marketplace/product/google/artifactregistry.googleapis.com)
* [Apigee APIs](https://console.cloud.google.com/marketplace/product/google/apigee.googleapis.com)
* [BigQuery API](https://console.cloud.google.com/marketplace/product/google/bigquery.googleapis.com)
* [BigQuery Connection API](https://console.cloud.google.com/marketplace/product/google/bigqueryconnection.googleapis.com)
* [Cloud Asset API](https://console.cloud.google.com/marketplace/product/google/cloudasset.googleapis.com)
* [Cloud Composer API](https://console.cloud.google.com/marketplace/product/google/composer.googleapis.com)
* [Cloud Functions](https://console.cloud.google.com/marketplace/product/google/cloudfunctions.googleapis.com)
* [Cloud SQL Admin](https://console.cloud.google.com/marketplace/product/google/sqladmin.googleapis.com)
* [Cloud Storage](https://console.cloud.google.com/marketplace/product/google/storage.googleapis.com)
* [Compute Engine API](https://console.cloud.google.com/marketplace/product/google/compute.googleapis.com)
* [Kubernetes Engine API](https://console.cloud.google.com/marketplace/product/google/container.googleapis.com)
* [Memorystore for Memcached API](https://console.cloud.google.com/marketplace/product/google/memcached.googleapis.com)
* [Memorystore for Redis API](https://console.cloud.google.com/marketplace/product/google/redis.googleapis.com)
* [OS Config API](https://console.cloud.google.com/marketplace/product/google/osconfig.googleapis.com)
* [Kubernetes Engine API](https://console.cloud.google.com/marketplace/product/google/container.googleapis.com)
* [Resource Manager API](https://console.cloud.google.com/marketplace/product/google/cloudresourcemanager.googleapis.com)
* [Spanner API](https://console.cloud.google.com/marketplace/product/google/spanner.googleapis.com)
* [Serverless VPC Access API](https://console.cloud.google.com/marketplace/product/google/vpcaccess.googleapis.com)

</details>

For each project in Vertex AI, enable the following:

<details>

<summary>Expand to view the list of permissions needed for Vertex AI projects</summary>

* [Cloud Storage API](https://console.cloud.google.com/marketplace/product/google/storage-component.googleapis.com)
* [DataCatalog API](https://console.cloud.google.com/marketplace/product/google/datacatalog.googleapis.com)
* [Dataflow AI API](https://console.cloud.google.com/marketplace/product/google/dataflow.googleapis.com)
* [DataForm API](https://console.cloud.google.com/marketplace/product/google/dataform.googleapis.com)
* [Notebooks AI API](https://console.cloud.google.com/marketplace/product/google/notebooks.googleapis.com)
* [Vertex AI API](https://console.cloud.google.com/marketplace/product/google/aiplatform.googleapis.com)
* [Vision AI API](https://console.cloud.google.com/marketplace/product/google/visionai.googleapis.com)

</details>

### Step 1: Configuring the integration in GCP

1. In the [G Suite admin console](https://admin.google.com/), navigate to **Security > API Controls > Manage Domain Wide Delegation**. Click **Add new**.
2. Click **Add new**.
3. Add the client ID and include the following scopes:
   * `https://www.googleapis.com/auth/admin.directory.group.readonly`
   * `https://www.googleapis.com/auth/admin.directory.group.member.readonly`
4. Go to the service account you created for this integration.&#x20;
5. Click **Keys**, then generate a key in JSON format.
6. Navigate to **Admin Roles > Groups Reader** and expand the Admins panel.
7. Click **Assign service accounts** then enter the email of the service account you created for this integration.

### Step 2: Configuring the integration in Cortex

1. From the main sidebar, select **Integrations**.&#x20;
2. Locate Google, then click **Install**. The Google side panel opens.
3. In the Google side panel, do the following:
   1. From the **Category** dropdown, select at least one category that applies to the integration (required).
   2. **Under Domain**, enter your organization's Google domain (required).
   3. Under **Service account user (email)**, enter the email address for the service account (required).
   4. Under **Credentials**, paste the service account JSON exactly as it is (required).
4. Click **Test connection**. A successful connection means your integration is configured correctly.
5. Click **Save**.

By default, a service depends on any resource whose Google Cloud tag has key "service" and value matching the service's [Cortex tag](/ingesting-data-into-cortex/entities-overview/entities#cortex-tag). After saving the configuration, you can customize the key name or leave it blank to use "service".

#### **Customizing the key name**

Follow the steps below to customize the key name.

1. From the main sidebar, select **Integrations**.&#x20;
2. Locate Google, then click **Settings**.
3. In the **Details** section, enter the key name under **Custom label key**.
4. Click **Save custom label key**.

{% hint style="info" %}
To modify an existing configuration, see [Modifying an integration configuration](https://docs.cortex.io/ingesting-data-into-cortex/integrations#modifying-an-integration-configuration).
{% endhint %}


# Connecting entities to Google Cloud Platform

Automatically import Google Cloud resources and Google Groups as entities, discover dependencies between them, and keep ownership in sync

{% hint style="info" %}
Cortex connects to many third-party vendors whose system interfaces frequently change. As a result, integration behavior or configuration steps may shift without notice. If you encounter unexpected issues, check with your system administrator or refer to the vendor's documentation for the most current information. Additionally, integration sync times vary and are subject to scheduling overrides and timing variance.
{% endhint %}

This article explains how to connect entities to GCP. For configuration instructions, see [Configuring the integration for Google Cloud Platform](/ingesting-data-into-cortex/integrations/google). For instructions on using the integration, see [Using the integration for Google Cloud Platform](/ingesting-data-into-cortex/integrations/google/using-the-integration-for-google-cloud-platform).

## Connecting an entity to Google Cloud Platform

Cortex gives you two ways to connect entities to Google Cloud: automatically or manually.&#x20;

Automatic connections rely on Cortex importing your Google Cloud resources and matching labels to discover dependencies, so entities stay up to date with little upkeep.&#x20;

Manual connections let you define ownership, infrastructure resources, dependencies, and SLOs directly in the entity descriptor, giving you more control when automatic discovery doesn't fit your setup.&#x20;

Most teams use a mix of both, depending on how consistently their Google Cloud resources are labeled.

### Automatically importing Google Cloud resources

{% hint style="warning" %}
This feature doesn't automatically import team entities. To import them, see [Adding team entities to Cortex](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/teams#adding-team-entities-to-cortex).
{% endhint %}

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 the **General** tab.
5. In the **Entity settings** section, toggle on **Auto import from AWS, Azure, and/or Google Cloud**.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/b8RUGBfD12ve9zDsLJfe" alt="" width="375"><figcaption></figcaption></figure></div>

### Manually importing Google Cloud resources via entity descriptor

To explicitly connect an entity to GCP, add the `x-cortex-infra` block to the entity's YAML, specifying the resource's name, project ID, and type.

<table><thead><tr><th width="158.5234375">Field</th><th width="458.97265625">Description</th><th align="center">Required?</th></tr></thead><tbody><tr><td><code>resourceName</code></td><td>Name of the GCP resource. For functions, use the format <code>location/function</code>.</td><td align="center"><i class="fa-check">:check:</i></td></tr><tr><td><code>projectId</code></td><td>The GCP project ID the resource belongs to</td><td align="center"><i class="fa-check">:check:</i></td></tr><tr><td><code>resourceType</code></td><td>The resource type, e.g. <code>function</code>, <code>storage</code></td><td align="center"><i class="fa-check">:check:</i></td></tr></tbody></table>

**Example**

```yaml
x-cortex-infra:
  Google Cloud:
    resources:
      - resourceName: us-central1/send-invoice
        projectId: cortex-production
        resourceType: function
      - resourceName: cortex-invoice-exports
        projectId: cortex-production
        resourceType: storage
```

## Ownership and dependencies for Google Cloud entities

### Syncing ownership from Google Groups

Cortex can use Google Groups as an ownership provider, automatically syncing group memberships so entity ownership always reflects your current mailing lists.&#x20;

{% hint style="info" %}
Cortex runs this ownership sync for Google teams every day at 9 a.m. UTC.
{% endhint %}

To assign a Google Group as an owner in your entity descriptor, use the group's full email address:

<table><thead><tr><th width="179.23828125">Field</th><th width="422.453125">Description</th><th align="center">Required?</th></tr></thead><tbody><tr><td><code>type</code></td><td>Must be <code>group</code></td><td align="center"><i class="fa-check">:check:</i></td></tr><tr><td><code>name</code></td><td>The full Google Group email address</td><td align="center"><i class="fa-check">:check:</i></td></tr><tr><td><code>provider</code></td><td>Must be <code>GOOGLE</code></td><td align="center"><i class="fa-check">:check:</i></td></tr><tr><td><code>description</code></td><td>Free-text description of the owner</td><td align="center"><i class="fa-xmark">:xmark:</i></td></tr></tbody></table>

**Example**

```yaml
x-cortex-owners:
  - type: group
    name: checkout-team@cortex.io
    provider: GOOGLE
    description: Owns the checkout service and its dependencies
```

### Discovering dependencies automatically

By default, Cortex looks for a `service` label on your Google Cloud resources and matches its value against each entity's [Cortex tag](/ingesting-data-into-cortex/entities-overview/entities#cortex-tag) to automatically map dependencies. If needed, you can [customize the label key](/ingesting-data-into-cortex/integrations/google#step-2-configuring-the-integration-in-cortex) in Cortex.

If you'd rather define these dependencies explicitly, add an `x-cortex-dependency` block to your entity descriptor:

<table><thead><tr><th width="158.5234375">Field</th><th width="458.97265625">Description</th><th align="center">Required?</th></tr></thead><tbody><tr><td><code>key</code></td><td>The label key on the GCP resource to match against</td><td align="center"><i class="fa-check">:check:</i></td></tr><tr><td><code>value</code></td><td>The label value on the GCP resource to match against</td><td align="center"><i class="fa-check">:check:</i></td></tr></tbody></table>

**Example**

```yaml
x-cortex-dependency:
  gcp:
    labels:
      - key: service
        value: checkout-service
      - key: env
        value: production
```

### Connecting SLOs

Reference a Service Level Objective (SLO) from Google Cloud Observability by adding its project and service ID to the entity's descriptor:

<table><thead><tr><th width="158.5234375">Field</th><th width="458.97265625">Description</th><th align="center">Required?</th></tr></thead><tbody><tr><td><code>projectId</code></td><td>The GCP project ID the SLO belongs to</td><td align="center"><i class="fa-check">:check:</i></td></tr><tr><td><code>serviceId</code></td><td>The unique ID from the service's page in Google Cloud Observability</td><td align="center"><i class="fa-check">:check:</i></td></tr></tbody></table>

**Example**

```yaml
x-cortex-slos:
  gcp:
    - projectId: cortex-production
      serviceId: iLE2e4HvR_service-checkout
    - projectId: cortex-production
      serviceId: iLE2e4HvR_service-billing
```

Find the `serviceId` value as the Unique ID on the [service page in Google Cloud Observability](https://console.cloud.google.com/monitoring/services).


# Using the integration for Google Cloud Platform

How to use the integration for GCP in Cortex

{% hint style="info" %}
Cortex connects to many third-party vendors whose system interfaces frequently change. As a result, integration behavior or configuration steps may shift without notice. If you encounter unexpected issues, check with your system administrator or refer to the vendor's documentation for the most current information. Additionally, integration sync times vary and are subject to scheduling overrides and timing variance.
{% endhint %}

This article explains how to use the integration for GCP. For configuration instructions, see [Configuring the integration for Google Cloud Platform](/ingesting-data-into-cortex/integrations/google). For instructions on connecting GCP to entities, see [Connecting entities to Google Cloud Platform](/ingesting-data-into-cortex/integrations/google/connecting-entities-to-google-cloud-platform).

## Viewing Google Cloud Observability data in entity pages

After connecting SLOs, Cortex surfaces Google Cloud Observability data directly on entity details pages:

* An entity's overview page shows a summary of its SLOs.
* Select **Monitoring > Google** in an entity's sidebar for more detail, including the SLO name, targets, status, current value, and the time range it's calculated over. For example, a time listed as "7 days ago" means the SLO covers the range from 7 days ago to now.

### Scorecards and CQL

With the Google integration, you can create Scorecard rules and write CQL queries based on GCP details, Google Cloud Observability SLOs, and Google teams.

See more examples in the [CQL Explorer](https://app.getcortexapp.com/admin/cql-explorer) in Cortex.

<details>

<summary>GCP details</summary>

Get the GCP details for the entity.

**Definition** - `gcp.details()`

**Examples**

A Scorecard might include a rule to verify that an entity has GCP details:

```
gcp.details() != null
```

You might include a rule to check whether any labels on the GCP recourse are titled `origin`:

```
jq(gcp.details(), ".resources[0].labels | any(\"origin\")")
```

</details>

<details>

<summary>SLOs</summary>

SLOs associated with the entity via ID or tags. You can use this data to check whether an entity has SLOs associated with it, and if those SLOs are passing.

**Definition** - `slos: List<SLO>`

**Example**

In a Scorecard, you can use this expression to make sure an entity is passing its SLOs:

```
slos().all((slo) => slo.passing) == true
```

Use this expression to make sure latency Service Level Indicator (SLI) value is above 99.99%:

```
slos().filter((slo) => slo.name.matchesIn("latency") and slo.sliValue >= 0.9999).length > 0
```

</details>

**Ownership CQL**

<details>

<summary>All ownership details</summary>

A special built-in type that supports a null check or a count check, used to enforce ownership of entities.

**Definition -** `ownership: Ownership | Null`

**Example**

An initial level in a security Scorecard might include a rule to ensure an entity has at least one team as an owner:

```
ownership.teams().length > 0
```

</details>

<details>

<summary>All owner details</summary>

List of owners, including team members and individual users, for each entity.

**Definition** - `ownership.allOwners()`

**Example**

The Scorecard might include a rule to ensure that entity owners all have an email set:

```
ownership.allOwners().all((member) => member.email != null)
```

</details>

<details>

<summary>Team details</summary>

List of teams for each entity.

**Definition** - `ownership.teams(): List<Team>`

**Example**

The Scorecard might include a rule to ensure that an entity owners all have a description and are not archived:

```
ownership.teams().all(team => team.description != null and team.isArchived == false)
```

</details>

## Viewing Google Cloud Platform integration logs <a href="#still-need-help" id="still-need-help"></a>

{% hint style="info" %}
This feature is available in Cortex cloud.
{% endhint %}

While viewing an integration's settings page, select the **Logs** tab to view error logs from the last 7 days. You can filter the logs list by configuration and by operation (for example, you could filter to view errors surfaced only via Scorecards).

<div align="left" data-with-frame="true"><figure><img src="/files/x8JmoPqXZTJ7YHeFJpOA" alt="The &#x27;Logs&#x27; tab on an integration&#x27;s settings page shows error information over the past 7 days."><figcaption></figcaption></figure></div>

Click into a row to get more information, including time stamp, status code, full error, and request path.

## Troubleshooting and FAQ <a href="#still-need-help" id="still-need-help"></a>

See frequently asked questions below.

**The GCP integration only supports a single service account. Is there a workaround?**

By default, GCP service accounts are restricted to the project they were created in. If other projects don’t explicitly allow that service account to access their resources, Cortex can’t collect data from them. To work around this, you can configure a [principal service account](https://docs.cloud.google.com/iam/docs/principals-overview) and associate it with multiple projects in GCP. Once the service account is linked to other projects, Cortex can use that service account to pull data from multiple GCP projects.

After creating a service account that is linked to a project, open your second project in GCP and go to **IAM & Admin > IAM >** Click **+Add**. Using the service account ID that you already created, add a principal to the project. Repeat these steps for each project.


# Grafana

{% hint style="info" %}
Cortex connects to many third-party vendors whose system interfaces frequently change. As a result, integration behavior or configuration steps may shift without notice. If you encounter unexpected issues, check with your system administrator or refer to the vendor's documentation for the most current information. Additionally, integration sync times vary and are subject to scheduling overrides and timing variance.
{% endhint %}

[Grafana](https://grafana.com/) is an open-source observability platform that provides monitoring and visual analytics for application performance. Use Grafana to [visualize](https://grafana.com/docs/grafana/latest/panels-visualizations/visualizations/) your data, from bar charts and histograms to pie charts and geomaps.

Integrating Grafana with Cortex allows you to:

* [View Grafana charts on entity pages](#viewing-grafana-graphs-on-an-entity) in Cortex
* Create [Scorecards](#scorecards-and-cql) that include rules related to Grafana dashboards

## How to configure Grafana with Cortex

### Prerequisites

Before getting started:

* Your Grafana dashboard must have [`allow_embedding` enabled](https://grafana.com/docs/grafana/next/setup-grafana/configure-grafana/#allow_embedding).
* Your [Grafana dashboard must be public](https://grafana.com/docs/grafana/latest/dashboards/share-dashboards-panels/shared-dashboards/) OR if you are on a [Self-managed Cortex](/self-managed) instance, then Cortex and Grafana must be accessible within the same private network (such as a VPN).
  * You will need the public embed link provided in the iframe snippet.

### Embed the chart in an entity's YAML file

Define the public embed link in the [entity descriptor YAML](/ingesting-data-into-cortex/entities-overview/entities#defining-entities-via-yaml-file) for each entity where you want to embed a chart.

1. For the entity where you want to embed a chart, open its YAML file.
   * You can do this locally if following a [GitOps](/configure/gitops) approach, or you can edit a YAML file directly in the Cortex UI on the [entity's details page](/ingesting-data-into-cortex/entities-overview/entities/details).
2. Add the `x-cortex-dashboards` block. Include the `type` (`grafana`) and the `url` (the public embed link you obtained from Grafana). See the example below:

```yaml
x-cortex-dashboards:
  embeds:
    - type: grafana
      url: https://snapshots.raintank.io/dashboard-solo/snapshot/y7zwi2bZ7FcoTlB93WN7yWO4aMiz3pZb?from=1493369923321&to=1493377123321&panelId=4&orgId=0
```

| Field  | Description                             | Required |
| ------ | --------------------------------------- | :------: |
| `type` | Type of embed (in this case, `grafana`) |   **✓**  |
| `url`  | Embed URL for the Grafana dashboard     |   **✓**  |

Repeat the steps above for each entity you want to add a Grafana chart to.

## Using the Grafana integration

### Viewing Grafana charts on an entity

Once you've defined the chart in an entity's YAML, you can view the graphs from an [entity's details page](/ingesting-data-into-cortex/entities-overview/entities/details).

In an entity's sidebar, click **Dashboard**. All charts defined in the entity descriptor will be embedded on this page.

### Scorecards and CQL

With the Grafana integration, you can create Scorecard rules and write CQL queries based on Grafana charts.

See more examples in the [CQL Explorer](https://app.getcortexapp.com/admin/cql-explorer) in Cortex.

<details>

<summary>Embeds</summary>

Query against embeds associated with an entity.

**Definition:** `embeds()`

**Example**

If Grafana charts are a core part of operations at your organization, you can set a Scorecard rule to make sure entities have embedded charts.

```
embeds().any((embed) => embed.type == "GRAFANA")
```

</details>

## Background sync

Grafana charts are updated in real time.

## FAQs and troubleshooting

**I've correctly added the embed URL, but the graph is showing an error or a blank screen.**

You may need to [enable embedding](https://grafana.com/docs/grafana/latest/administration/configuration/#allow_embedding) in your Grafana instance.

## Still need help?[​](https://docs.cortex.io/docs/reference/integrations/aws#still-need-help) <a href="#still-need-help" id="still-need-help"></a>

The following options are available to get assistance from the Cortex Customer Engineering team:

* **Email**: <help@cortex.io>, or open a support ticket in the in app Resource Center
* **Slack**: Users with a connected Slack channel will have a workflow added to their account. From here, you can either @CortexTechnicalSupport or add a `:ticket:` reaction to a question in Slack, and the team will respond directly.

Don’t have a Slack channel? Talk with your Customer Success Manager.


# Harness

Configuring the integration for Harness

{% hint style="info" %}
Cortex connects to many third-party vendors whose system interfaces frequently change. As a result, integration behavior or configuration steps may shift without notice. If you encounter unexpected issues, check with your system administrator or refer to the vendor's documentation for the most current information. Additionally, integration sync times vary and are subject to scheduling overrides and timing variance.
{% endhint %}

This article explains how to configure the integration for Harness. For instructions on using the integration, including triggering Harness pipelines from a Workflow, see [Using the integration for Harness](/ingesting-data-into-cortex/integrations/harness/using-the-integration-for-harness).

## Why use the integration for Harness

Harness is where your team builds and deploys software. Connecting it to Cortex ties your delivery pipelines to the services in your catalog, so your CI/CD platform and your system of record stay in sync.

With the Harness integration, you can:

* **Connect all of your Harness accounts.** Cortex supports multiple configurations, so you can connect several Harness accounts and tie each one to entities using its own alias.
* **Keep internally hosted instances private.** Use Cortex Axon Relay to connect a self-managed Harness instance without exposing it to the internet. The relay agent runs in your network and injects your API key locally, so credentials never leave your environment.
* **Verify your setup before you commit.** Test a configuration directly from the settings page to confirm Cortex can reach your Harness account, whether you use a personal access token or a service account token.
* **Run pipelines from a Workflow.** Use the **Execute pipeline** block to trigger a Harness pipeline as a step in a Cortex Workflow, without building a custom webhook trigger for each pipeline.

## Configuring Harness

There are two options for integrating Harness: the default token configuration method and Cortex Axon Relay, a relay broker that allows you to securely connect your internally hosted Harness instance.

### Prerequisites

1. Users with the `Configure Integrations` permission can configure Harness.
2. An API key in Harness. Cortex supports both personal access tokens and service account tokens. For instructions, refer to the [Harness API key documentation](https://developer.harness.io/docs/platform/automation/api/add-and-manage-api-keys/).
3. Your Harness account identifier. You can find this in Harness under **Account settings**, or in your Harness URL.

### **Configuring Harness with a token**

1. From the main sidebar, select **Integrations**.
2. Locate Harness, then click **Install**. The Harness side panel opens.
3. In the Harness side panel, click **Token**.
4. Do the following:
   1. From the **Category** dropdown, select at least one category that applies to the integration (required).
   2. Under **Configuration alias**, enter the alias you'll use to tie entity registrations to different configuration accounts (required).
   3. Under **Account ID**, enter your Harness account identifier (required).
   4. Under **API key**, enter your Harness API key (required). This can be a personal access token or a service account token.
   5. Under **Host**, enter the URL of your self-managed Harness instance. If you leave this field blank, Cortex defaults to `https://app.harness.io`.
5. Click **Test connection**. A successful connection means your integration is configured correctly.
6. Click **Save**.

### Configuring Harness with Cortex Axon Relay

Use this option if your Harness instance is hosted in your own network and can't be reached directly by Cortex.

1. From the main sidebar, select **Integrations**.
2. Locate Harness, then click **Install**. The Harness side panel opens.
3. Click **Relay**.
4. Do the following:
   1. From the **Category** dropdown, select at least one category that applies to the integration (required).
   2. Under **Configuration alias**, enter the alias you'll use to tie entity registrations to different configuration accounts (required).
   3. Under **Account ID**, enter your Harness account identifier (required).
   4. Under **Host**, enter the URL of your self-managed Harness instance. If you leave this field blank, Cortex defaults to `https://app.harness.io`.
5. Click **Save**.
6. Set up the Axon Relay agent in your network. See [Internally hosted integrations](/ingesting-data-into-cortex/integrations/axon-relay) for instructions. For Harness, the relay agent routes requests to your Harness instance and injects your API key, so your credentials never leave your network.

### Using multiple Harness configurations

The Harness integration supports multiple configurations. To add another:

1. From the main sidebar, select **Integrations**.
2. Locate Harness, then click **Settings**.
3. In the upper-right corner of the page, click **Add configuration**.
4. Follow the steps in either [Configuring Harness with a token](#configuring-harness-with-a-token) or [Configuring Harness with Axon Relay](#configuring-harness-with-axon-relay).

Each configuration requires an alias, which ties entity registrations to a specific account. If no alias is specified, Cortex uses the default configuration. To set a default:

1. From the main sidebar, select **Integrations**.
2. Locate Harness, then click **Settings**.
3. Click the **pencil icon** next to the configuration that should be the default.
4. Toggle on **Set as default**. If you only have one configuration, it's automatically set as the default.


# Using the integration for Harness

How to use the integration for Harness in Cortex

{% hint style="info" %}
Cortex connects to many third-party vendors whose system interfaces frequently change. As a result, integration behavior or configuration steps may shift without notice. If you encounter unexpected issues, check with your system administrator or refer to the vendor's documentation for the most current information. Additionally, integration sync times vary and are subject to scheduling overrides and timing variance.
{% endhint %}

This article explains how to use the integration for Harness. For configuration instructions, see [Configuring Harness](/ingesting-data-into-cortex/integrations/harness).

After you configure Harness, you can trigger Harness pipelines directly from a Cortex Workflow using the **Execute pipeline** block. This replaces the custom webhook and raw HTTP approach, so you don't need to build and maintain a webhook trigger for every pipeline you want to run from Cortex.

## Prerequisites

1. A configured Harness integration.&#x20;
2. The Harness API key used in that configuration must have permission to execute the pipelines you want to run.
3. Permission to create or edit Workflows in Cortex. See [Creating a Workflow](/streamline/workflows/create).

## Triggering a Harness pipeline from a Workflow

The **Execute pipeline** block runs a Harness pipeline as a step in a Workflow. You can chain it with other blocks, for example to require a manual approval before a deploy, or to post the run link to Slack after the pipeline starts.

**To add the Execute pipeline block to a Workflow**:

1. From the main sidebar, select **Workflows**.
2. Do one of the following:
   * Select the **All** tab to search and filter across all of your organization's Workflows.
   * Select the **Mine** tab to search and filter only the Workflows you own.
   * Note that Cortex saves your selection and restores it the next time you open this page.
3. Locate the Workflow you want to edit, click the **overflow menu** next to it, then select **Edit workflow**.
4. Click the **+ icon**. The **Search for blocks** window opens.
5. Search for **Harness**, then select **Execute pipeline**.
6. In the side panel, configure the block metadata:
   1. **Block name** - Optionally, change the name of the block. The name auto-populates based on the block name.
   2. **Slug** - Optionally, change the slug. The slug auto-populates based on the block name and is made up of letters, digits, and hyphens.
   3. **Alias** - From the dropdown, select the Harness configuration the block should use (required). See [Selecting the right configuration](#selecting-the-right-configuration) for more information.
   4. Enter the required pipeline details:
      1. Under **Organization identifier**, enter the identifier of the Harness organization that owns the pipeline (required).
      2. Under **Project identifier**, enter the identifier of the Harness project that owns the pipeline (required).
      3. Under **Pipeline identifier**, enter the identifier of the pipeline you want to run (required).
   5. Optionally, add runtime inputs:
      1. Under **Runtime inputs**, enter the pipeline's runtime input values as YAML. Use this to pass values the pipeline expects at execution time, such as an environment or an image tag.
      2. Under **Notes**, enter a short description of the run. Cortex passes this to Harness so the execution is easier to identify in the Harness UI.
7. Click **Save**.

You can reference values from earlier blocks in any of these fields using Workflow state. See [Referencing Workflow state in a block](/streamline/workflows/blocks#referencing-a-workflow-state-in-a-block).

### Block outputs

When the pipeline is triggered successfully, the block returns:

* `execution_id` - The identifier of the Harness pipeline execution that was started.
* `status` - The execution status Harness reported at trigger time.
* `response` - The full response object from Harness, for any field not surfaced above.

Reference these in later blocks the same way you reference any other block output, for example to build a link to the execution or to branch on the returned status.

{% hint style="info" %}
The **Execute pipeline** block is synchronous. It returns as soon as Harness acknowledges the run, so `status` reflects the state of the execution at trigger, not the final result of the pipeline. To act on the pipeline's outcome, poll Harness in a later block or have the pipeline notify Cortex when it finishes.
{% endhint %}

### How the block authenticates

The block authenticates with the API key stored in the Harness configuration you select, so the pipeline runs as the owner of that key. It doesn't run as the person who started the Workflow. Keep this in mind when you set up Harness permissions and when you review pipeline audit logs, since every run started from Cortex is attributed to the key's owner.

### Selecting the right configuration

If you have more than one Harness configuration, always select an explicit **Configuration alias** on the block. A block left on the default configuration uses the default account's credentials, which is a common cause of unexpected `401` errors when you meant to use a different account.

This matters most for internally hosted instances. See [Using the block with Cortex Axon Relay](#using-the-block-with-cortex-axon-relay).

## Using the block with Cortex Axon Relay

The **Execute pipeline** block works with internally hosted Harness instances connected through [Cortex Axon Relay](/ingesting-data-into-cortex/integrations/harness#configuring-harness-with-cortex-axon-relay). The relay agent runs in your network and injects your Harness API key locally, so your credentials never leave your environment. For setup instructions, see Internally hosted integrations.

Two things to know when you use the block over the relay:

* **Select the relay-backed configuration alias on the block.** Cortex only routes a request through the relay when the block names a configuration alias. If the block is left on the default configuration, the request goes directly to Harness instead of through the relay and fails to authenticate.
* **Your Harness API key stays on-premises.** Cortex sends the request with a placeholder credential, and the relay agent replaces it with your real key before the request reaches Harness. Both personal access tokens and service account tokens are supported.

## Viewing Harness integration logs

{% hint style="info" %}
This feature is available in Cortex cloud.
{% endhint %}

While viewing an integration's settings page, select the **Logs** tab to view error logs from the last 7 days. You can filter the logs list by configuration and by operation (for example, you could filter to view errors surfaced only via Scorecards).

<div align="left" data-with-frame="true"><figure><img src="/files/x8JmoPqXZTJ7YHeFJpOA" alt="The &#x27;Logs&#x27; tab on an integration&#x27;s settings page shows error information over the past 7 days."><figcaption></figcaption></figure></div>

Click into a row to get more information, including time stamp, status code, full error, and request path.

## Troubleshooting and FAQ

See frequently asked questions below.

<details>

<summary><strong>The block returns a 401 or authentication error</strong></summary>

Check the following:

* The block has an explicit **Configuration alias** selected. If it's set to the default configuration and your Harness instance is behind Cortex Axon Relay, the request bypasses the relay and fails.
* The API key in the selected configuration is still valid, and its owner has permission to execute the pipeline.
* The organization and project identifiers on the block match the account the selected configuration points at.

</details>

<details>

<summary><strong>A relay-backed Harness configuration shows as failing validation</strong></summary>

A newly created relay-backed configuration can show a failed connection test on the integration settings page, even when the setup is correct. Click **Test connection** on the configuration to re-run the check. If it still fails, confirm the Axon Relay agent is running and can reach your Harness host.

</details>

<details>

<summary><strong>The pipeline started, but the Workflow moved on before it finished</strong></summary>

This is expected. The **Execute pipeline** block returns as soon as Harness acknowledges the run. Use the returned `execution_id` in a later block to check the execution's final state in Harness.

</details>


# Humanitec

{% hint style="info" %}
Cortex connects to many third-party vendors whose system interfaces frequently change. As a result, integration behavior or configuration steps may shift without notice. If you encounter unexpected issues, check with your system administrator or refer to the vendor's documentation for the most current information. Additionally, integration sync times vary and are subject to scheduling overrides and timing variance.
{% endhint %}

[Humanitec](https://humanitec.com/) offers products to build on top of your Engineering Operations Platform for containerized workloads.

Integrating Humanitec with Cortex allows you to run a Humanitec pipeline directly from Cortex.

## How to integrate Humanitec with Cortex

### Prerequisites

Before getting started:

* You should have an app with a working pipeline configured in Humanitec.
* Create a service user in Humanitec, and create an [API token in Humanitec](https://developer.humanitec.com/platform-orchestrator/docs/platform-orchestrator/reference/api-references/#authentication) for the service user.

### Step 1: Create a Workflow in Cortex

1. Follow the instructions to [begin creating a Workflow](/streamline/workflows/create#step-1-choose-a-template-or-a-blank-workflow) and [configure its basic settings](/streamline/workflows/create#step-2-configure-your-workflow-settings).
2. Add an **HTTP request** block to your Workflow. Configure the block:
   * **Block name**: Enter a descriptive name for the block.
   * **Slug**: Enter a unique identifier for the block.
   * **HTTP method**: Select `POST`.
   * **URL**: Enter a Humanitec API URL based on the Humanitec call [`createPipelineRun`](https://api-docs.humanitec.com/#tag/PipelineRuns/operation/createPipelineRun), e.g., `https://api.humanitec.io/orgs/<your-Humanitec-org>/<your-app-ID>/pipelines/<pipeline-ID>/runs`
3. At the bottom of the side panel, click **Save**.
4. Make any other necessary changes to your Workflow, then in the upper right corner of the page, click **Save workflow**.

Alternatively, you can also use an **Async HTTP request** block in your Workflow, using the [Humanitec action `actions/humanitec/http@v1`](https://developer.humanitec.com/platform-orchestrator/docs/integration-and-extensions/humanitec-pipelines/available-actions/#actionshumanitechttpv1) to call back to Cortex.

### Step 2: Run the Workflow

* At the top of your Workflow in Cortex, click **Run**.

In your Humanitec workspace under your app's pipelines, you will see the run listed under the **Runs** tab:

<figure><img src="/files/n9o0b2AVLD81anbB0Bcx" alt="Runs are listed in Humanitec under the app&#x27;s pipeline runs tab."><figcaption></figcaption></figure>

## Example using Cortex with AWS, Humanitec, and Terraform

See the video below where a member of the Humanitec team walks through advanced end-to-end setup on AWS using Cortex, Humanitec as the orchestrator, and Terraform modules deployed via ECS runners. The video demonstrates detecting a policy violation and remediating it.

{% embed url="<https://www.youtube.com/watch?t=44s&v=iFYO0TFF5cs>" %}


# incident.io

Configuring the integration for incident.io

{% hint style="info" %}
Cortex connects to many third-party vendors whose system interfaces frequently change. As a result, integration behavior or configuration steps may shift without notice. If you encounter unexpected issues, check with your system administrator or refer to the vendor's documentation for the most current information. Additionally, integration sync times vary and are subject to scheduling overrides and timing variance.
{% endhint %}

This article explains how to configure the integration for incident.io. For instructions on using the integration, see [Using the integration for incident.io](/ingesting-data-into-cortex/integrations/incidentio/using-the-integration-for-incident.io).

## **Why use the integration for incident.io**

Incidents don't happen in a vacuum; they happen to services, teams, and systems. The integration for incident.io connects Cortex and incident.io so your teams can see, track, and act on operational health in one place with Cortex serving as the source of truth for both platforms.

Without this integration, incident data lives in isolation. Engineers have to cross-reference incident.io and Cortex manually to understand which services are struggling, which teams are burdened by recurring incidents, or whether an entity meets your organization's reliability standards. The integration eliminates that gap.

Once connected, active and historical incidents surface automatically on entity pages, giving anyone viewing a service a real-time picture of its operational state. You can also [trigger incidents](/ingesting-data-into-cortex/integrations/incidentio/using-the-integration-for-incident.io#triggering-an-incident) in incident.io directly from Cortex without switching tools, which is useful when you're already deep in an entity's details and need to escalate fast. And because incident.io can pull Cortex teams and catalog entities directly, your team and service data stays consistent across both tools without manual upkeep.

Beyond visibility, the integration unlocks measurement. With Cortex [Scorecards](/standardize/scorecards) and [CQL](/standardize/cql), you can write rules that evaluate incident behavior at scale, e.g. flagging entities with too many high-severity incidents in the past 90 days or ensuring every service has a registered incident.io configuration. This turns incident data into an input for engineering standards, not just an artifact to review after the fact.

In short: the incident.io integration makes incidents a first-class signal in Cortex, so you can hold services accountable to reliability expectations and give teams the context they need to respond faster.

### **Using Cortex as a source of truth in incident.io**

incident.io natively supports pulling Cortex teams and catalog entities into incident.io, so Cortex can serve as the source of truth for team and service data across both platforms. This is configured from the incident.io side. See [incident.io's Cortex integration docs](https://docs.incident.io/catalog/cortex) for setup instructions.

## Configuring incident.io

### Prerequisites

1. Users with the `Configure Integrations` permission can configure incident.io.
2. Create an [incident.io API key](https://app.incident.io/settings/api-keys) with the following scopes:
   * `Create incidents`
   * `View all incident data, including private incidents`
   * `View data like public incidents and organization settings`
   * `View catalog types and entries`

**To install incident.io in Cortex**:

1. From the main sidebar, select **Integrations**.
2. Locate incident.io, then click **Install**. The incident.io side panel opens.
3. In the incident.io side panel, do the following:
   1. From the **Category** dropdown, select at least one category that applies to the integration (required).
   2. Under **Configuration alias**, enter the alias you'll use to tie entity registrations to different configuration accounts (required).
   3. Under **API key**, enter your incident.io API key (required).
4. Click **Test connection**. A successful connection means your integration is configured correctly.
5. Click **Save**.

{% hint style="info" %}
To modify an existing configuration, see [Modifying an integration configuration](https://docs.cortex.io/ingesting-data-into-cortex/integrations#modifying-an-integration-configuration).
{% endhint %}

### **Using multiple incident.io configurations**[**​**](https://docs.cortex.io/docs/reference/integrations/incidentio#configure-the-integration-for-multiple-propsintegration-accounts)

The incident.io integration supports multiple configurations. To add another:

1. From the main sidebar, select **Integrations**.
2. Locate incident.io, then click **Settings**.
3. In the upper-right corner of the page, click **Add configuration**.
4. Follow the steps in [Configuring incident.io](#configuring-incident.io).

Each configuration requires an alias, which ties entity registrations to a specific account. If no alias is specified, Cortex uses the default configuration. To set a default:

1. From the main sidebar, select **Integrations**.
2. Locate incident.io, then click **Settings**.
3. Click the **pencil icon** next to a configuration.
4. Toggle on **Set as default**. If you only have one configuration, it's automatically set as the default.


# Using the integration for incident.io

How to use the integration for incident.io in Cortex

{% hint style="info" %}
Cortex connects to many third-party vendors whose system interfaces frequently change. As a result, integration behavior or configuration steps may shift without notice. If you encounter unexpected issues, check with your system administrator or refer to the vendor's documentation for the most current information. Additionally, integration sync times vary and are subject to scheduling overrides and timing variance.
{% endhint %}

This article explains how to use the integration for incident.io. For configuration instructions, see [Configuring the integration for incident.io](/ingesting-data-into-cortex/integrations/incidentio).

## Connecting an entity to incident.io

By default, Cortex tries to automatically match entities to their corresponding custom field values in incident.io.

Cortex first looks up the custom field value using the entity's name, then falls back to its identifier. For example, if your entity is named "Payment Service," Cortex looks for a matching custom field value in incident.io of either `Payment Service` or `payment-service`.

### Editing the entity descriptor

```yaml
x-cortex-incident-io:
  customFields:
  - name: Service
    value: Payment Service
    alias: prod-account
```

<table><thead><tr><th width="89.046875">Field</th><th width="397.5546875">Description</th><th align="center">Required</th></tr></thead><tbody><tr><td><code>name</code></td><td>Name for the entity (from <code>customFieldName</code>)</td><td align="center"><strong>✓</strong></td></tr><tr><td><code>value</code></td><td>Display name for the entity in Cortex</td><td align="center"><strong>✓</strong></td></tr><tr><td><code>alias</code></td><td>Alias for the configuration in Cortex (only needed if you have opted into multi-account support)</td><td align="center"></td></tr></tbody></table>

```yaml
x-cortex-incident-io:
  customFields:
  - id: SVC_12345
    value: payment-service
    alias: prod-account
```

<table><thead><tr><th width="88.69140625">Field</th><th width="397.55078125">Description</th><th align="center">Required</th></tr></thead><tbody><tr><td><code>id</code></td><td>ID for the entity (from <code>customFieldID</code>)</td><td align="center"><strong>✓</strong></td></tr><tr><td><code>value</code></td><td>Tag for the entity in Cortex</td><td align="center"><strong>✓</strong></td></tr><tr><td><code>alias</code></td><td>Alias for the configuration in Cortex (only needed if you have opted into multi-account support)</td><td align="center"></td></tr></tbody></table>

### Viewing incident.io information on entity pages

Once the integration is configured, incident data appears in two places on an [entity's details page](/ingesting-data-into-cortex/entities-overview/entities/details):

* When there are active (unresolved) incidents associated with an entity, an active incident card appears at the top of the **Overview** tab.
* Full incident history is available under **On-call & incidents** in the entity's sidebar.

## Using the incident.io integration

### Triggering an incident

1. In Cortex, navigate to an entity.&#x20;
2. From the entity's left sidebar, select **Incidents**.
3. In the upper-right corner of the **Incidents** page, click **Trigger incident**. The **Trigger incident** side panel opens.
4. Do the following:
   1. Under **Title**, enter a name for the incident (required).&#x20;
   2. Under **Description**, enter a description of the incident.
   3. From the **Urgency** dropdown, select a severity level.
5. Click **Trigger incident**.&#x20;
6. Click **Click here** to view the incident in incident.io.
7. Click **Close** to collapse the **Trigger incident** side panel.

### Creating Scorecard rules and writing CQL queries with the incident.io integration

See examples below. More examples are available in the [CQL Explorer](https://app.getcortexapp.com/admin/cql-explorer).

<details>

<summary>Check if incident.io service is set</summary>

Check if entity has a registered incident.io custom field value in its entity descriptor.

If no registration exists, Cortex will try to automatically detect which corresponding incident.io custom field value is associated with the entity.

**Definition:** `incidentio (==/!=) null`

**Example**

For a Scorecard focused on operational maturity, you can use this expression to make sure each entity has an incident.io project set:

```
incidentio != null
```

</details>

<details>

<summary>Incidents</summary>

List incidents, filterable by severity and status.

* Created at
* Mode
* Name
* Severity
* Status
* Summary
* Type
* URL

**Definition:** `incidentio.incidents()`

**Examples**

To assess entities' health in a Scorecard, you can write a rule to make sure a given entity has fewer than three incidents with a severity of SEV1:

```
incidentio.incidents(severity = ["SEV1"]).length < 3
```

You can also use this expression to query for entities that have two or fewer critical incidents in the last three months:

```
  incidentio.incidents(severity = ["Critical"]).filter((incident) => incident.createdAt.fromNow() > duration("-P90D")).length <= 2
```

</details>

## Viewing incident.io integration logs <a href="#still-need-help" id="still-need-help"></a>

{% hint style="info" %}
This feature is available in Cortex cloud.
{% endhint %}

While viewing an integration's settings page, select the **Logs** tab to view error logs from the last 7 days. You can filter the logs list by configuration and by operation (for example, you could filter to view errors surfaced only via Scorecards).

<div align="left" data-with-frame="true"><figure><img src="/files/x8JmoPqXZTJ7YHeFJpOA" alt="The &#x27;Logs&#x27; tab on an integration&#x27;s settings page shows error information over the past 7 days."><figcaption></figcaption></figure></div>

Click into a row to get more information, including time stamp, status code, full error, and request path.


# Instana

{% hint style="info" %}
Cortex connects to many third-party vendors whose system interfaces frequently change. As a result, integration behavior or configuration steps may shift without notice. If you encounter unexpected issues, check with your system administrator or refer to the vendor's documentation for the most current information. Additionally, integration sync times vary and are subject to scheduling overrides and timing variance.
{% endhint %}

## Overview

[IBM Instana Observability](https://www.ibm.com/products/instana) is a tool used for monitoring and performance management. Integrate Instana with Cortex allows you to pull in services from Instana.

## How to configure Instana with Cortex

### Prerequisite

Before getting started, [create an API token in Instana](https://www.ibm.com/docs/en/instana-observability/current?topic=api-authenticating-instana-rest).

### Configure the integration in Cortex

1. In Cortex, navigate to the [Instana settings page](https://app.getcortexapp.com/admin/integrations/instana):
   1. Click **Integrations** from the main nav. Search for and select **Instana**.
2. Click **Add configuration**.
3. Configure the Instana integration form:
   * **Tenant endpoint**: Enter your tenant endpoint. This can be found in your Instana app URL.
   * **API token**: Enter the API token you generated in Instana.
4. Click **Save**.

## How to connect Cortex entities to Instana

### Import services from Instana

Cortex automatically syncs from Instana APM at 7 a.m. UTC.

See the [Create services documentation](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/add-services#creating-services) for instructions on importing entities.

### Import Instana services from Discovery audit

Cortex will pull recent changes from Instana into the [discovered entities list](/ingesting-data-into-cortex/entities-overview/entities/discovery-audit). Here, you can find new entities in Instana that have not been imported into the catalog.

## View integration logs <a href="#still-need-help" id="still-need-help"></a>

{% hint style="info" %}
This feature is available in Cortex cloud.
{% endhint %}

While viewing an integration's settings page, select the **Logs** tab to view error logs from the last 7 days. You can filter the logs list by configuration and by operation (for example, you could filter to view errors surfaced only via Scorecards).

<div align="left" data-with-frame="true"><figure><img src="/files/x8JmoPqXZTJ7YHeFJpOA" alt="The &#x27;Logs&#x27; tab on an integration&#x27;s settings page shows error information over the past 7 days."><figcaption></figcaption></figure></div>

Click into a row to get more information, including time stamp, status code, full error, and request path.

## Still need help?[​](https://docs.cortex.io/docs/reference/integrations/aws#still-need-help) <a href="#still-need-help" id="still-need-help"></a>

The following options are available to get assistance from the Cortex Customer Engineering team:

* **Email**: <help@cortex.io>, or open a support ticket in the in app Resource Center
* **Slack**: Users with a connected Slack channel will have a workflow added to their account. From here, you can either @CortexTechnicalSupport or add a `:ticket:` reaction to a question in Slack, and the team will respond directly.

Don’t have a Slack channel? Talk with your Customer Success Manager.


# Jenkins

{% hint style="info" %}
Cortex connects to many third-party vendors whose system interfaces frequently change. As a result, integration behavior or configuration steps may shift without notice. If you encounter unexpected issues, check with your system administrator or refer to the vendor's documentation for the most current information. Additionally, integration sync times vary and are subject to scheduling overrides and timing variance.
{% endhint %}

[Jenkins](https://www.jenkins.io/) is an open source automation server which enables developers to build, test, and deploy software.

Integrating Jenkins with Cortex allows you to:

* Send information about Jenkins deploys into Cortex
  * This data appears on [entity detail pages](#view-jenkins-deploys-on-entity-pages-in-cortex).
* Use [Cortex Workflows to kick off a Jenkins pipeline](#kick-off-a-jenkins-pipeline-in-a-cortex-workflow)
* See [deploy data for Jenkins in Eng Intelligence](#see-jenkins-data-in-eng-intelligence)

## How to integrate Jenkins with Cortex

### Prerequisites

Before getting started:

* Create a [Jenkins API key](https://www.jenkins.io/doc/book/system-administration/authenticating-scripted-clients/).
  * Note: This is only necessary if you plan to use Jenkins blocks in Cortex Workflows.

### Step 1: Install the Cortex Deployer app

This integration uses the Cortex Deployer app, an open-source app that makes it easier for teams to push information about deploys to Cortex. This app leverages Cortex's [deploy REST endpoint](/api/readme/deploys).

* Install the [Cortex Deployer app](https://github.com/cortexapps/solutions/tree/master/tools/deploy).

### Step 2: Add a step to your Jenkins pipeline

#### Jenkins secrets

To use the Cortex Deployer app, you will need the `x-cortex-tag` and a Cortex API token. In the example below, both are defined as [Jenkins secrets](https://www.jenkins.io/doc/developer/security/secrets/).

#### Jenkinsfile

To push information to Cortex about a deploy event, add a step to your Jenkins pipeline. Below is a snippet of what a Jenkinsfile may look like.

```
pipeline {
    agent any
    environment 
    stages {
        stage('update-cortex') { 
            steps {
                sh "docker run cortexapp/deployer:0.2 -i \"Jenkins deploy\" -k $CORTEX_API_TOKEN -s $GIT_COMMIT -t DEPLOY -e Prod -c '' -g $CORTEX_TAG" 
            }
        }
    }
}
```

For more details about the options passed to the Docker image, please refer to the [Deployer repository](https://github.com/cortexapps/solutions/tree/master/tools/deploy).

### Step 3: Configure Jenkins in Cortex to enable Jenkins Workflow blocks <a href="#still-need-help" id="still-need-help"></a>

If you plan to use Jenkins blocks in Cortex Workflows, you will need to configure Jenkins in your Cortex workspace:

1. In Cortex, navigate to the [Jenkins settings page](https://app.getcortexapp.com/admin/integrations/jenkins):
   * Click **Integrations** from the main nav. Search for and select **Jenkins**.
2. Click **+Add configuration**.
3. Configure the integration form:
   * **Alias**: Enter an alias for the integration.
   * **Username**: Enter your Jenkins username.
   * **API key**: Enter your Jenkins API key.
   * **Host**: Enter the base URL of your Jenkins instance.
4. Click **Save**.

## Using the Jenkins integration <a href="#still-need-help" id="still-need-help"></a>

### View Jenkins deploys on entity pages in Cortex

After you configure the integration, you will see data about Jenkins deploys in an [entity's details page](/ingesting-data-into-cortex/entities-overview/entities/details):

* On the entity overview, Jenkins deploys will appear under the **Latest events** section.
* In the entity's sidebar, click **Events** to see a full list of events for the entity, including deploy events from Jenkins.
* In the entity's sidebar, click **CI/CD > Deploys** to see data from the [Cortex deploys API](/api/readme/deploys), including Jenkins deploys.

### Kick off a Jenkins pipeline in a Cortex Workflow

You can use a Workflow to kick off a Jenkins pipeline. See the [Jenkins Workflow guide](/guides/operational-readiness/jenkins-workflow) for more information.

### See Jenkins data in Eng Intelligence

Since the Jenkins integration uses Cortex's [deploys API endpoint](/api/readme/deploys), Jenkins data is included in Eng Intelligence deploy metrics. Learn more about [Eng Intelligence in the docs](/improve/eng-intelligence).

### View integration logs <a href="#still-need-help" id="still-need-help"></a>

{% hint style="info" %}
This feature is available in Cortex cloud.
{% endhint %}

While viewing an integration's settings page, select the **Logs** tab to view error logs from the last 7 days. You can filter the logs list by configuration and by operation (for example, you could filter to view errors surfaced only via Scorecards).

<div align="left" data-with-frame="true"><figure><img src="/files/x8JmoPqXZTJ7YHeFJpOA" alt="The &#x27;Logs&#x27; tab on an integration&#x27;s settings page shows error information over the past 7 days."><figcaption></figcaption></figure></div>

Click into a row to get more information, including time stamp, status code, full error, and request path.

## Still need help?[​](https://docs.cortex.io/docs/reference/integrations/aws#still-need-help) <a href="#still-need-help" id="still-need-help"></a>

The following options are available to get assistance from the Cortex Customer Engineering team:

* **Email**: <help@cortex.io>, or open a support ticket in the in app Resource Center
* **Slack**: Users with a connected Slack channel will have a workflow added to their account. From here, you can either @CortexTechnicalSupport or add a `:ticket:` reaction to a question in Slack, and the team will respond directly.

Don’t have a Slack channel? Talk with your Customer Success Manager.


# Jira

{% hint style="info" %}
Cortex connects to many third-party vendors whose system interfaces frequently change. As a result, integration behavior or configuration steps may shift without notice. If you encounter unexpected issues, check with your system administrator or refer to the vendor's documentation for the most current information. Additionally, integration sync times vary and are subject to scheduling overrides and timing variance.
{% endhint %}

[Jira](https://www.atlassian.com/software/jira/guides/getting-started/introduction) is a project management tool that helps developers track and manage bugs and work items.

By integrating Jira with Cortex, you can drive improvements and coordinate issue management across teams. Through the integration, you can create Jira work items directly in Cortex based on an Initiative's action items. The integration also allows you to enhance insights into a number of key values for your entities:

* Customer facing incidents
* Security tickets
* Ongoing projects

## How to configure Jira with Cortex

It is possible to configure the integration with a Jira Cloud instance or a self-hosted Jira instance (using either basic auth or OAuth). You can also use Cortex Axon Relay to securely integrate your on-premises data. See the tabs below for instructions on each option.

{% tabs %}
{% tab title="Jira Cloud" %}
**Jira Cloud**

**Prerequisites**

Before configuring Cortex with Jira Cloud:

* Create a [Jira API token](https://id.atlassian.com/manage-profile/security/api-tokens). To generate a token, you must have the `Browse users and groups` permissions in Jira and access to the needed Jira projects.
* If you are using a scoped token, you will need your [Atlassian Cloud ID](https://support.atlassian.com/jira/kb/retrieve-my-atlassian-sites-cloud-id/). Scoped tokens must include the following scopes:
  * Read: `jira-work`, `jira-user`, `project-category:jira`, `project:jira`, `project-version:jira`, `project.property:jira`, `project.component:jira`, `issue-type:jira`, `issue-type-hierarchy:jira`, `user:jira`, `avatar:jira`, `project.avatar:jira`, `application-role:jira`, `group:jira`
  * Write: `jira-work`

**Configure the integration in Cortex**

1. In Cortex, navigate to the [Jira settings page](https://app.getcortexapp.com/admin/integrations/jira):
   * Click **Integrations** from the main nav. Search for and select **Jira**.
2. Click **Add configuration**. then select **Cloud** for the integration type.
   * If you are using a scoped token, select **Cloud (scoped token)**.
3. In the Jira integration modal, "Jira Cloud" is selected by default in the upper right corner. Configure the integration form:
   * **Account alias**: Enter an alias for your account.
   * **Subdomain**: Enter the subdomain for your Jira instance.
     * For example, this field would take `cortex-docs` from `https://cortex-docs.atlassian.net`.
   * **Base URL**: This field automatically populates `atlassian.net`.
     * If you are using a legacy Jira Cloud instance (i.e., you access your Jira instance on `jira.com`), change the base URL from the dropdown.
   * **Email**: Enter the email address associated with the user who generated the token in Jira.
     * Note: The email address associated with a given Jira token **must** match the email address of the user associated with that token.
   * **API token**: Enter your Jira API token.
4. Click **Save**.
   {% endtab %}

{% tab title="On-prem (Basic)" %}
**Jira on-prem (Basic)**

**Prerequisite**

If you're using a self-hosted instance of Jira, you'll need to verify that your Cortex instance is able to reach the Jira instance.\
\
We route our requests through a static IP address. Reach out to support at <help@cortex.io> to receive details about our static IP. If you're unable to directly allowlist our static IP, you can route requests through a secondary proxy in your network that has this IP allowlisted and have that proxy route traffic to your Jira instance.

**Configure the integration in Cortex**

1. In Cortex, navigate to the [Jira settings page](https://app.getcortexapp.com/admin/settings/jira):
   1. In Cortex, click your avatar in the lower left corner, then click **Settings**.
   2. Under "Integrations," click **Jira**.
2. Click **Add configuration**.
3. In the upper right corner of the Jira integration modal, click the dropdown labeled `Cloud`. Select `On-prem (basic auth)`.
4. Configure the Jira integration form:
   * **Account alias**: Enter an alias for your account.
   * **Host**: Enter the URL for your Jira on-premises host.
   * **Frontend host**: Enter the URL for your Jira on-premises frontend host.
   * **Username** and **Password**: Enter your Jira username and password.
5. Click **Save**.
   {% endtab %}

{% tab title="On-prem (OAuth)" %}
**Jira on-prem (OAuth)**

**Prerequisites**

To integrate Cortex with Jira using OAuth, you must be running a self-hosted Jira instance with Jira server version 8.22 or higher.

If you're using a self-hosted instance of Jira, you'll need to verify that your Cortex instance is able to reach the Jira instance.\
\
We route our requests through a static IP address. Reach out to support at <help@cortex.io> to receive details about our static IP. If you're unable to directly allowlist our static IP, you can route requests through a secondary proxy in your network that has this IP allowlisted and have that proxy route traffic to your Jira instance.

**Step 1: Create an application link from Jira**

1. In your Jira server, navigate to Settings > Applications > Application Links. Click **Create link**.
2. Configure the application link settings:
   * **Application type**: Select `External`.
   * **Direction**: Select `Incoming`.
   * **Redirect URL**: For default configuration, enter the URL of your Cortex instance appended with `/oauth/internal/jira`. For a non-default configuration, enter the URL of your Cortex instance appended with `/oauth/internal/jira/`.
   * **Permission**: Select `write`.
3. Click **Save**.
4. The application link will have an associated client ID and client secret. Copy these values and store them in a secure location, as you will need them in the next steps.

**Step 2: Configure the integration in Cortex**

1. In Cortex, navigate to the [Jira settings page](https://app.getcortexapp.com/admin/settings/jira):
   1. In Cortex, click your avatar in the lower left corner, then click **Settings**.
   2. Under "Integrations," click **Jira**.
2. Click **Add configuration**.
3. In the upper right corner of the Jira integration modal, click the dropdown labeled `Cloud`. Select `On-prem (OAuth)`.
4. Configure the Jira integration form:
   * **Account alias**: Enter an alias for your account.
   * **Host**: Enter the URL for your Jira on-premises host.
   * **Frontend host**: Enter the URL for your Jira on-premises frontend host.
   * **Client ID** and **Client secret**: Enter the client ID and secret associated with the application link you created in the previous steps.
5. Click **Save**.
6. You will be redirected to the Jira settings page. Click **Install** next to your integration name.
   * A confirmation modal will appear, asking you to allow Cortex access to your Jira account.
   * The accessing user can be a user persona or a system account. We recommend using a system account to maintain your organization's access in case the user who set up the integration leaves your organization.
     {% endtab %}

{% tab title="Relay broker" %}
**Configure Jira with Cortex Axon Relay**

See [Internally hosted integrations](/ingesting-data-into-cortex/integrations/axon-relay) for instructions.
{% endtab %}
{% endtabs %}

**Configure the integration for multiple Jira accounts**[**​**](https://docs.cortex.io/docs/reference/integrations/jira#configure-the-integration-for-multiple-propsintegration-accounts)

The Jira integration has multi-account support. You can add a configuration for each additional by repeating the process above.

Each configuration requires an alias, which Cortex uses to correlate the designated with registrations for various entities. Registrations can also use a default configuration without a listed alias. You can edit aliases and default configurations from the Jira page in your Cortex settings. Select the edit icon next to a given configuration and toggle **Set as default** on. If you only have one configuration, it will automatically be set as the default.

## Set a default JQL query for your Jira integration

You can set a custom JQL query for your [Jira integration instances](#tenant-level) and for [individual entities](#entity-level). This allows you to filter which Jira work items are surfaced on entity pages or in other places in Cortex where CQL is used.

The default JQL applies to `jira.issues()` and `jira.numOfIssues()` but not to `jira.rawJql()`.

{% hint style="warning" %}
Note that if you define additional filter logic for your default JQL query when writing a Scorecard rule, you must add that logic in a filter clause. See [Adding filter logic to the default JQL query in a Scorecard](#adding-filter-logic-to-the-default-jql-query-in-a-scorecard) for more information.
{% endhint %}

{% tabs %}
{% tab title="Tenant level" %}
**Set default JQL query at a tenant level**

From the [Jira settings page](https://app.getcortexapp.com/admin/settings/jira) in Cortex, you can set a custom JQL query for your Jira integration.

When Cortex queries for Jira work items, the `statusCategory` is directly grabbed from the [API response](https://docs.atlassian.com/DAC/javadoc/jira/reference/com/atlassian/jira/issue/status/category/StatusCategory.html).

The default query — `statusCategory in ("To Do", "In Progress")` — will filter your Jira tickets to display only those with `To Do` and `In Progress` statuses, excluding closed tickets. The `indeterminate` status category will map to `In Progress` according to the API. Cortex does not use the `status` field for mapping these categories.

Entering a custom JQL query on the Jira integration settings page allows you to override the default for all entities in your workspace. To map work items with a custom status, you can write a custom JQL query that uses `status` instead of `statusCategory`.
{% endtab %}

{% tab title="Entity level" %}
**Set default JQL query at entity level**

You can configure default JQL for entities in their [entity YAML](/ingesting-data-into-cortex/entities-overview/entities#defining-entities-via-yaml-file). For example:

```yaml
x-cortex-issues:
    jira:
      projects:
      - name: PROJECT_A
        alias: Jira Project A
      defaultJql: "project = project_a"
```

{% hint style="info" %}
Entity-level default JQL is not applied to project management metrics in Data Explorer. To filter those metrics, use the available filters in the Data Explorer UI.
{% endhint %}
{% endtab %}
{% endtabs %}

### Fallback logic for default JQL

It is possible to set custom JQL at both the entity and tenant level, but note the fallback logic:

1. If any JQL is passed into a query, Cortex uses that.
2. If not, Cortex uses entity-level default JQL.
3. If not, Cortex uses tenant-wide default JQL.
4. If none, then no JQL is used for filtering.

### Adding filter logic to the default JQL query in a Scorecard

The CQL statement will use the default JQL setting in a Scorecard rule only if you do not define additional filter logic. Any filter logic applied to the statement will override the default JQL query.

To work around this: If you need to include additional filter logic on your query in a Scorecard, you can move the filter logic to the filter clause.

For example, if your default JQL query is set to `"project = project_a"`, then you can add `jira.issues()` to a Scorecard rule to automatically surface only the work items relating to Project A. However, you cannot use `jira.issues(some_other_filter_logic)` in a Scorecard; Cortex will not append your default JQL to the additional filter logic.

In this example, the workaround would be to add a filter clause:\
`jira.issues().filter(some_other_filter_logic)`.

## How to connect Cortex entities to Jira labels, components, or projects

### Discovery

By default, Cortex will tie Jira tickets to entities by searching for any tickets where the `label`, `component`, or `project` field for the work item includes the [Cortex tag](/ingesting-data-into-cortex/entities-overview/entities#cortex-tag). For example, if your Cortex tag is “my-entity,” then the corresponding tickets in Jira should have “my-entity” as a label, component, or project.

If your Jira label/component/project doesn't cleanly match the Cortex tag, you can override this in the Cortex [entity descriptor](/ingesting-data-into-cortex/entities-overview/entities#defining-entities-via-yaml-file).

Without an override, a ticket's label, component, or project must **exactly match** the Cortex tag in the descriptor.

### Connecting via YAML or the Cortex UI

{% tabs %}
{% tab title="Cortex UI" %}
**Connect Jira entities via the Cortex UI**

1. Navigate to an [entity's details page](/ingesting-data-into-cortex/entities-overview/entities/details) in Cortex.
2. In the upper right corner, click **Configure entity**.\\

   <div align="left"><figure><img src="/files/fEmHBrIb2mtAqwGC1cAq" alt="In the upper right side of an entity, click &#x22;Configure entity.&#x22;"><figcaption></figcaption></figure></div>
3. Click the **Project management** tab, then click **+Add**.\\

   <div align="left"><figure><img src="/files/kk3PZy29TlklC80hsEfh" alt="Click Project management, then click Add." width="563"><figcaption></figcaption></figure></div>
4. In the side panel, configure the details:
   * **Jira service type**: Choose component, label, or project.
   * **Alias**: If you have multiple Jira configurations, select which one this service is associated with.
   * **Name**: Enter the name of the service.
5. At the bottom of the side panel, click **Add**.
   {% endtab %}

{% tab title="Entity YAML" %}
**Editing the entity descriptor**

If you need to override automatic discovery, you can define `x-cortex-issues` blocks in your Cortex entity descriptor.

Note: For all of the following, `alias` is optional, and the default Jira configuration will be used if not provided. You can use Jira `labels`, `components`, or `projects` to match entities.

Each of these blocks has the same field definitions.

| Field   | Description                                                                                      | Required |
| ------- | ------------------------------------------------------------------------------------------------ | :------: |
| `name`  | Label name in Jira                                                                               |   **✓**  |
| `alias` | Alias for the configuration in Cortex (only needed if you have opted into multi-account support) |          |

```yaml
x-cortex-issues:
  jira:
    labels:
      - name: labelA
        alias: alias1
      - name: labelB
```

```yaml
x-cortex-issues:
  jira:
    components:
      - name: component1
        alias: alias1
```

```yaml
x-cortex-issues:
  jira:
    projects:
      - name: project1
        alias: alias1
```

```yaml
x-cortex-issues:
  jira:
    labels:
      - name: label1
      - name: label2
      - name: label3
    components:
      - name: component1
      - name: component2
```

By default, Cortex will surface outstanding issues per entity in the catalog with a default [JQL](https://www.atlassian.com/blog/jira-software/jql-the-most-flexible-way-to-search-jira-14) query: `statusCategory in ("To Do", "In Progress")`. If you'd like to override this, you can provide a new default query with:

```yaml
x-cortex-issues:
  jira:
    defaultJql: 'status = "In Progress"'
```

{% endtab %}
{% endtabs %}

### Identity mappings

Cortex maps Jira accounts to team members defined in the team catalog, so you do not need to define Jira users in a team member's YAML file.

You can confirm that users' Jira accounts are connected from the [Jira user mappings section in Settings](https://app.getcortexapp.com/admin/settings/jira-mappings).

## Using the Jira integration

#### Entity pages

Once the integration is established, you'll be able to pull in data about the work items in any linked Jira instances for a given entity:

* **Number of issues:** Unresolved issues associated with an entity that have the JQL status "in progress" or "to do"
* **Number of issues from JQL query:** Issues associated with an entity that match an arbitrary JQL query

Cortex will tie Jira tickets directly to entities within the catalog. Click **Issue tracking** in the entity's sidebar to see associated Jira tickets.

From this tab you can find a list of all issues with a label that matches the Cortex tag.

* **Key:** The issue key (or "ticket number") for a Jira work item.
* **Issue summary:** Title of the Jira work item and the user designated as the issue reporter.
* **Assignee:** User designated as the work item assignee.
* **Priority:** The work item's priority level in Jira - Lowest, Low, Medium, High, Highest. This will display with the [icon](https://support.atlassian.com/jira-service-management-cloud/docs/what-are-priority-levels-in-jira-service-management/) that corresponds to the priority level in your Jira instance.
* **Created:** Date the work item was created.
* **Due:** Due date for the work item, if applicable.

This list will also be available from a team's homepage when the team's Cortex tag matches a `label`, `component`, or `project` in Jira.

#### Initiatives

Initiatives allow you to set deadlines for specific rules or a set of rules in a given Scorecard and send notifications to users about upcoming due dates.

From the Issues tab of an Initiative, you can automatically create a Jira ticket from a failing rule.

Read about creating Jira issues from Initiatives in the documentation: [Creating issues based on initiatives](/improve/initiatives/issue-config).

#### Dev homepage

The Jira integration enables Cortex to pull information about issues into the [dev homepage](/streamline/homepage). You can find open work items assigned to you under the [Issues tab](https://app.getcortexapp.com/admin/home?activeTab=Issues). The work items that display will depend both on the Jira instances you've connected and the JQL query defined in Settings.

Work items are refreshed every 5 minutes. You can use the **Refresh work items** button to manually refresh issues at any point.

### Scorecards and CQL

With the Jira integration, you can create Scorecard rules and write CQL queries based on Jira work items.

See more examples in the [CQL Explorer](https://app.getcortexapp.com/admin/cql-explorer) in Cortex.

<details>

<summary>Issues</summary>

Number of **unresolved** issues associated with the entity, where unresolved is defined as the JQL status = "Open" OR status = "To Do".

**Definition:** `jira.numOfIssues()`

**Example**

For a Scorecard measuring entity maturity, you can use this expression to make sure entities have fewer than 3 Jira issues:

```
jira.numOfIssues() <= 10
```

</details>

<details>

<summary>Issues from JQL query</summary>

Number of issues associated with the entity based on arbitrary JQL query.

**Definition:** `jira.numOfIssues(jqlQuery: Text | Null)`

**Example**

For a more specific rule in an entity maturity Scorecard, you can use this expression with a JQL query to make sure entities have no more than 3 open customer-facing tickets.

```
jira.numOfIssues("status = \"Open\" and labels = \"customer-facing\"") <= 3
```

</details>

### View integration logs <a href="#still-need-help" id="still-need-help"></a>

{% hint style="info" %}
This feature is available in Cortex cloud.
{% endhint %}

While viewing an integration's settings page, select the **Logs** tab to view error logs from the last 7 days. You can filter the logs list by configuration and by operation (for example, you could filter to view errors surfaced only via Scorecards).

<div align="left" data-with-frame="true"><figure><img src="/files/x8JmoPqXZTJ7YHeFJpOA" alt="The &#x27;Logs&#x27; tab on an integration&#x27;s settings page shows error information over the past 7 days."><figcaption></figcaption></figure></div>

Click into a row to get more information, including time stamp, status code, full error, and request path.

## Background sync

The [engineering homepage](/streamline/homepage) runs a background job every 5 minutes to refresh the Issues tab.

## FAQs and troubleshooting

**I've added a Jira integration, but I'm not sure what JQL is being generated to query Jira.**

When running Scorecard rules, Cortex appends `AND (component = cortex-tag OR labels = cortex-tag OR project = cortex-tag)` to the [JQL you defined](#jira-default-jql), where `cortex-tag` is the [Cortex tag](/ingesting-data-into-cortex/entities-overview/entities#cortex-tag).

**My Scorecard rules are failing, even though there are tickets in my Jira instance.**

Make sure that the ticket has a label, component, or project that matches **exactly** with the Cortex tag or the list defined in your entity descriptor.

**I received "Configuration error: Integration error for Jira: Unexpected HTTP response 0".**

When using Jira Cloud, you'll need to create a Jira API token and add it on in Jira Settings in Cortex. The email address in Settings **must be the same as the user that the token is associated with**. Cortex also expects only the subdomain of your Jira instance, not the entire URL.

**I received "Configuration error: Jira: Unexpected HTTP response 403: Forbidden".**

1. Make sure that the entity name in Cortex matches the label, component, or project name in Jira.
2. Make sure the subdomain and base URL correspond with the Jira instance you're trying to connect.
3. Verify that the Jira token you added is still valid. You can run the following [curl command](https://developer.atlassian.com/cloud/jira/platform/basic-auth-for-rest-apis/#supply-basic-auth-headers) to confirm:

```
curl -D- \
-X GET \
-H "Authorization: Basic {{your-token}}" \
-H "Content-Type: application/json" \
"https://{{your-domain}}.atlassian.net/rest/api/2/issue/{{valid-ticket-number}}"
```

**I configured the integration, but I am not seeing Work Items populate.**

The background job fetches work items every 5 minutes. However, a fresh integration configuration may result in longer waiting times, as it also fetches historical data.

## Still need help?[​](https://docs.cortex.io/docs/reference/integrations/aws#still-need-help) <a href="#still-need-help" id="still-need-help"></a>

The following options are available to get assistance from the Cortex Customer Engineering team:

* **Email**: <help@cortex.io>, or open a support ticket in the in app Resource Center
* **Slack**: Users with a connected Slack channel will have a workflow added to their account. From here, you can either @CortexTechnicalSupport or add a `:ticket:` reaction to a question in Slack, and the team will respond directly.

Don’t have a Slack channel? Talk with your Customer Success Manager.


# Kubernetes

{% hint style="info" %}
Cortex connects to many third-party vendors whose system interfaces frequently change. As a result, integration behavior or configuration steps may shift without notice. If you encounter unexpected issues, check with your system administrator or refer to the vendor's documentation for the most current information. Additionally, integration sync times vary and are subject to scheduling overrides and timing variance.
{% endhint %}

[Kubernetes](https://kubernetes.io) is a container orchestration system that automates software deployment, scaling, and management. The Cortex K8s agent is a lightweight agent that collects information from your cluster (Deployments, StatefulSets, Argo Rollouts, and CronJobs) and surfaces it in your Cortex workspace's catalog, Scorecards, and more.

Integrating Kubernetes with Cortex allows you to:

* [Discover and import services](#connecting-cortex-entities-to-kubernetes) directly from K8s clusters into Cortex, making it easy to keep the catalog in sync with what's actually running in production
* [View Kubernetes data on entity pages](#view-kubernetes-data-on-entity-pages) in Cortex, giving you visibility into your infrastructure and how services are deployed
* Create [Scorecards](#scorecards-and-cql) to track progress and drive alignment on projects relating to Kubernetes, and to enforce Kubernetes best practices

## How to configure Kubernetes with Cortex

### Prerequisites

Before getting started:

* [Reach out to the Cortex customer engineering team](#still-need-help) for the Helm chart used for deployment and a username and password.
* [Generate an API key](/configure/settings/api-keys) in Cortex.
  * The API key should have the `User (edit catalog entities)` role at a minimum.
  * Note: It is also possible to programmatically create your API key via the [Cortex API](/api/readme/api-keys).

#### Security considerations

The Cortex k8s agent uses a push model that ensures you do not need to expose your cluster to the public internet.

Additionally, the Helm chart comes with a predefined `ClusterRole` that provides the correct RBACs:

* **Permissions:** `["get", "watch", "list"]`
* **Resources:** `["deployments", "services", "pods", "replicationcontrollers", "statefulsets", "rollouts", "cronjobs"]`
* **API groups:** `["apps", "argoproj.io", "batch"]`

Communication out of the cluster to Cortex happens over HTTPS. There is no inbound traffic to the agent.

### Install the Cortex k8s agent in your Kubernetes cluster

To connect Cortex to your Kubernetes instance, you’ll need to install the Cortex k8s agent in your Kubernetes cluster. The agent is lightweight and adds negligible impact to your cluster.

1. Create a Docker image pull secret:

   ```
   kubectl create secret docker-registry cortex-docker-registry-secret \
   --docker-server=ghcr.io \
   --docker-username={provided by Cortex} \
   --docker-password={token provided to you by the Cortex team} \
   --docker-email={email address}
   ```
2. Run the following command, replacing `cortex-key` with the value of your Cortex API key, to create a secret in your cluster:

   ```
   kubectl create secret generic cortex-key --from-literal api-key=
   ```
3. Run the following command to install the Helm chart provided by Cortex:

   ```
   helm install  ./helm-chart
   ```

## Connecting Cortex entities to Kubernetes

### Discovery

By default, Cortex will use the [Cortex tag](/ingesting-data-into-cortex/entities-overview/entities#cortex-tag) (e.g. `my-entity`) as the "best guess" for Kubernetes resource. For example, if your Cortex tag is `my-entity`, then the corresponding resource in Kubernetes should also be `my-entity`.

If your Kubernetes resource don’t cleanly match the Cortex tag, you can override this in the Cortex entity descriptor.

### Methods for mapping Kubernetes resources

See the table below for the methods of mapping resources to entities:

<table><thead><tr><th width="230">Method</th><th width="154.5728759765625">Use case</th><th>Action</th></tr></thead><tbody><tr><td><a href="#annotation">Annotation-based mapping</a></td><td>Services that own their K8s infra</td><td>By default, Cortex maps Kubernetes deployments with a <code>cortex.io/tag</code> annotation to Cortex entities with the same tag.<br><br>Annotation mapping should be at the default absolute path of <code>.metadata.annotations."cortex.io/tag"</code>.</td></tr><tr><td><a href="#label-based">Label-based auto-mapping</a></td><td>Shared infra or external-managed services</td><td>Specify a list of label keys in the Kubernetes integration settings page of your Cortex workspace</td></tr><tr><td><a href="#entity-yaml">Manual link in entity YAML</a></td><td>Complex or legacy workloads</td><td>Add the resource manually to your entity descriptor</td></tr></tbody></table>

See the tabs below to learn how to use each option:

{% tabs %}
{% tab title="Annotation" %}
**Annotation**

You can link your Kubernetes deployment to a Cortex entity by [adding an annotation](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) to your k8s deployment metadata. By default, Cortex maps Kubernetes deployments with a `cortex.io/tag` annotation to Cortex entities with the same tag.

Use `cortex.io/tag` as the key and use the value of `x-cortex-tag` in the Cortex entity's `cortex.yaml` as the value.

For example, if the `cortex.yaml` file is:

```yaml
openapi: 3.0.1
info:
  title: My Service
  x-cortex-tag: my-service
  x-cortex-type: service
  description: This is my cool service.
```

Then the `deployment.yaml` file should be configured as:

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-name
  namespace: my-namespace
  annotations:
    cortex.io/tag: my-service
```

**Customize annotation mapping**

It is possible to customize annotation mapping in Cortex:

<details>

<summary>Customize annotation mapping</summary>

1. In Cortex, navigate to the [Kubernetes settings page](https://app.getcortexapp.com/admin/integrations/k8s):
   * Click **Integrations** from the main nav. Search for and select **Kubernetes**.
2. Optionally enter a JQ mapping into the **Annotation mapping** field.
3. Click **Save mapping**.

Note that Cortex looks at the top-level metadata annotations on the Deployment object itself (`metadata.annotations`), not the pod template annotations (`spec.template.metadata.annotations`).

If your automapping is not working as expected, make sure the annotation mapping is at the correct default absolute path of `.metadata.annotations."cortex.io/tag"`, or update the annotation mapping in the K8s configuration page to match the exact absolute path of the Cortex tag.

**Example**

Let's say, for example, your `deployment.yaml` includes `my.service` as the `cortex.io/tag`:

```yaml
metadata:
  name: my-name
  namespace: my-namespace
  annotations:
    cortex.io/tag: my.service
```

If this deployment should be mapped to a Cortex entity with the tag `my-entity`, you can enter the following JQ expression to convert all periods in the deployment annotation tag to dashes:

```
.metadata.annotations."cortex.io/tag" | gsub("\\."; "-")
```

</details>
{% endtab %}

{% tab title="Label-based" %}
**Label-based auto-mapping**

You can override [Cortex tag](/ingesting-data-into-cortex/entities-overview/entities#cortex-tag) discovery and have Cortex discover Kubernetes resources using their metadata labels instead:

<details>

<summary>Customize label-based auto-mapping</summary>

1. In Cortex, navigate to [**Integrations > Kubernetes**](https://app.getcortexapp.com/admin/integrations/k8s).
2. Under the **K8s auto-mapping customization**, specify a list of metadata label keys.
3. When you are finished, click **Save**.

Once the list is saved, Cortex will discover all Kubernetes resources with metadata labels with the following criteria:

* The resource's spec metadata key contains any of the specified labels
* The key values match a Cortex entity tag

**Example**

For example, let's say you have two Cortex entities (`example` and `entity`), and the following Kubernetes JSON blob:

```
{
  "name": "Sample Kubernetes resource",
  "metadata": {
    "labels": {
      "app": "example",
      "another": "entity"
    }
  }
}
```

By default, `example` and `entity` will have no Kubernetes resource mappings. If the list of metadata labels is set to `["app"]`, then entity `example` will be associated with "Sample Kubernetes resource." If the list is set to `["app", "another"]`, then both `example` and `entity` will be associated with the resource.

</details>
{% endtab %}

{% tab title="Entity YAML" %}
**Editing the entity descriptor**

Cortex accepts several k8s resources, which can be on different clusters or of different types: deployments, ArgoCD rollout, StatefulSet, and CronJob.

All of these resource types have the same field definitions:

| Field        | Description                                                    | Required |
| ------------ | -------------------------------------------------------------- | :------: |
| `identifier` | `namespace/name` as found in Kubernetes                        |   **✓**  |
| `cluster`    | The name of the cluster, which is set when deploying the agent |          |

**Deployments**

```yaml
x-cortex-k8s:
  deployment:
    - identifier: namespace/name
      cluster: dev
    - identifier: experiment/scratch
      cluster: dev
    - identifier: default/cortex
      cluster: prod
```

**ArgoCD Rollout**

```yaml
x-cortex-k8s:
  argorollout:
    - identifier: namespace/name
      cluster: dev
```

**StatefulSet**

```yaml
x-cortex-k8s:
  statefulset:
    - identifier: namespace/name
      cluster: dev
```

**CronJob**

```yaml
x-cortex-k8s:
  cronjob:
    - identifier: namespace/name
      cluster: dev
```

{% endtab %}
{% endtabs %}

### Import entities from Kubernetes

See the [Create services documentation](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/add-services#creating-services) for instructions on manually importing entities.

## Using the Kubernetes integration

### View Kubernetes data on entity pages

Kubernetes deployment data will be available in the **Kubernetes** block on the [entity details pages](/ingesting-data-into-cortex/entities-overview/entities/details) for entities imported from Kubernetes or linked to a k8s resource.

<figure><img src="/files/wjBj9kRNaT2DwZeYidNB" alt="Kubernetes data appears in the Kubernetes block on the entity details page overview."><figcaption></figcaption></figure>

In the entity's sidebar, click **Environments** to see Kubernetes deployments, clusters, active replicas, and pending deployments, as well as:

* **Replicas:** Number of available, ready, and desired replicas.
* **Containers:** Resource containers, including requested memory, memory limit, and CPU data. Also includes the full container definition.

<figure><img src="/files/94VYxUW4N1igIYuaim60" alt=""><figcaption></figcaption></figure>

### Scorecards and CQL

With the Kubernetes integration, you can create Scorecard rules and write CQL queries based on Kubernetes resources. For an example, see Cortex's prebuilt [Kubernetes Deployment Baseline Scorecard](/guides/migrations-and-modernization/accelerate-migration-to-k8s#create-a-kubernetes-scorecard) template.

See more rule examples in the [CQL Explorer](https://app.getcortexapp.com/admin/cql-explorer) in Cortex.

<details>

<summary>Cluster information</summary>

Data about k8s clusters associated with a given entity.

**Definition:** `k8s.clusters()`

**Examples**

You can use the `k8s.clusters()` expression in the Query Builder to find all clusters that start with "dev":

```
k8s.clusters.all((cluster) => cluster.name.matches("""dev-.*"""))
```

Or any cluster named "prod":

```
k8s.clusters.any((cluster) => cluster.name.matches("prod"))
```

</details>

<details>

<summary>Deployment labels</summary>

Checks deployment metadata.

**Definition:** `k8s.metadata()`

**Examples**

You can use this expression in a production readiness Scorecard to check ownership:

```
k8s.metadata().labels.any((label) => label.get("ownership") == "ownership_team")
```

This rule checks an entity's metadata labels for the ownership annotation and will pass if "ownership\_team" is defined.

You can also use this expression in the Query Builder to find all k8s deployments with the label "environment":

```
k8s.metadata().labels.all((label) => label.containsKey("environment")) == true
```

Or you could refine the query further to find k8s deployments with an "environment" label and that are in production:

```
k8s.metadata().labels.all((label) => label.get("environment")?.matches("prod")") == true
```

</details>

<details>

<summary>K8s resource is set for entity</summary>

Checks whether a k8s resource of any type is associated with an entity.

**Definition:** `k8s != null`

**Example**

For a Scorecard focused on automation or development maturity, you can set a rule to make sure a k8s resource is mapped:

```
k8s != null
```

</details>

<details>

<summary>Kubernetes spec YAML</summary>

The [Cortex k8s agent](#install-the-cortex-k8s-agent-in-your-kubernetes-cluster) periodically sends the raw spec definitions for all entities. The spec JSON is equivalent to the **root spec field** of the entity descriptor (deployments, StatefulSet, etc.) and fully conforms to that format.

You can find the official documentation for these resource objects in the [Kubernetes Workload Docs](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/).

You can use this list of JSON specs combined with jq or [Open Policy Agent (OPA) language](https://www.openpolicyagent.org/docs/v0.52.0/) to write complex assertions such as "all resources must have specific annotations set" or "all containers should have a CPU resource limit defined."

The list of JSON specs can also be filtered to only ones in a specific cluster by specifying the cluster name: `k8s.spec("prod")`.

**Definition:** `k8s.spec()`

**Examples**

You can use this expression to write a wide range of rules. For a best practices Scorecard, you can make sure that resource definitions have set CPU requests:

```
jq(k8s.spec(), ".[].template.spec.containers[].resources.requests.cpu") != null
```

Or that all resource definitions expose only TCP ports:

```
jq(k8s.spec(), ".[].template.spec.containers[].ports[].protocol") == "TCP"
```

</details>

<details>

<summary>Replica information</summary>

Number of replicas available, current, desired, ready, unavailable, or updated.

**Definition:** `k8s.replicas()`

**Example**

You can use this expression in a development maturity Scorecard to make sure an entity has at least two available instances:

```
k8s.replicas().numAvailable >= 2
```

**View integration logs**

{% hint style="info" %}
This feature is available in Cortex cloud.
{% endhint %}

While viewing an integration's settings page, select the **Logs** tab to view error logs from the last 7 days. You can filter the logs list by configuration and by operation (for example, you could filter to view errors surfaced only via Scorecards).

<div align="left" data-with-frame="true"><figure><img src="/files/x8JmoPqXZTJ7YHeFJpOA" alt="The &#x27;Logs&#x27; tab on an integration&#x27;s settings page shows error information over the past 7 days."><figcaption></figcaption></figure></div>

Click into a row to get more information, including time stamp, status code, full error, and request path.

</details>

## Background sync

The Cortex k8s agent is a cron job that runs every 5 minutes by default.

## FAQs and troubleshooting

#### **When I try to import entities, I don't see all the supported workload types (deployments, ArgoCD rollout, StatefulSet, CronJob)**

Make sure that the types you expected to see are in the cluster you are attempting to import.

#### **Missing namespaces from Kubernetes discovery**

If you're using [Cortex's k8s agent](#cortex-k8s-agent) to import entities into Cortex but don't see all expected namespaces during the import process, make sure `app.namespace` is commented out in `values.yaml`:

```
app:
  # baseURL: 
  baseURL:
  keySecret:
  # namespace: exampleNamespace
```

If `app.namespace` is defined the Cortex k8s agent will only be able to discover services from that namespace. This behavior can be confirmed with a backend log similar to:

```
INFO 1 --- [ scheduling-1] k8sagent : Looking for stateful sets in namespace 
```

Once `app.namespace` is commented out, restart your pods. You will then be able to see all expected namespaces when importing new services.

#### **Helm chart and deprecated Kubernetes Docker registry**

If your Cortex agent in Kubernetes clusters is blocked due to deprecation of Docker registry after an upgrade, you can make these direct edits using the same credentials:

1. **Access the image** from `ghcr.io` instead of `docker.pkg.github.com`.

   ```
   image: ghcr.io/cortexapps/k8s-agent...
   ```
2. **Update the registry secret**, setting the server to `https://ghcr.io`.

If you are unable to make these changes, please reach out to <help@cortex.io> and request a new Helm chart with this change already reflected.

#### **Failing ArgoCD rollouts error in the k8s agent**

When running the self-hosted Kubernetes agent successfully, users may see failing ArgoCD rollouts errors while not using this tool.

```
Error polling argocd rollouts from Kubernetes API

io.kubernets.client.openapi.ApiException:
[...]
  at com.brainera.k8sSDKClient.getArgoRollouts(k8sClient.kt:101) ~[app:/na]
```

Cortex logs this exception for verbosity - this error is harmless if not using ArgoCD tool.

#### **Can I deploy on prem if I don’t use Kubernetes?**

Yes - the Cortex Helm chart deploys two Cortex-specific pods from images for the frontend and backend, as well as a data store. You can use these images to run Docker containers on other platforms, such as ECS.

## Still need help?[​](https://docs.cortex.io/docs/reference/integrations/aws#still-need-help) <a href="#still-need-help" id="still-need-help"></a>

The following options are available to get assistance from the Cortex Customer Engineering team:

* **Email**: <help@cortex.io>, or open a support ticket in the in app Resource Center
* **Slack**: Users with a connected Slack channel will have a workflow added to their account. From here, you can either @CortexTechnicalSupport or add a `:ticket:` reaction to a question in Slack, and the team will respond directly.

Don’t have a Slack channel? Talk with your Customer Success Manager.


# LaunchDarkly

{% hint style="info" %}
Cortex connects to many third-party vendors whose system interfaces frequently change. As a result, integration behavior or configuration steps may shift without notice. If you encounter unexpected issues, check with your system administrator or refer to the vendor's documentation for the most current information. Additionally, integration sync times vary and are subject to scheduling overrides and timing variance.
{% endhint %}

[LaunchDarkly](https://launchdarkly.com/) is a feature flag management platform.

Integrating Cortex with LaunchDarkly allows you to:

* Track LaunchDarkly feature flags on entities in the catalog.
* Create [Scorecards](/standardize/scorecards) that track progress and drive alignment on projects involving your LaunchDarkly feature flags.
* Perform tasks relating to LaunchDarkly feature flags as a part of a [Workflow](/streamline/workflows).
  * For example, you can include a "Create feature flag" step within a Workflow.

## How to configure LaunchDarkly with Cortex

### Prerequisites

Before getting started, create a [LaunchDarkly access token](https://app.launchdarkly.com/settings/authorization) with:

* The `Writer` role
  * If you are not adding LaunchDarkly-related tasks to your [Workflows](/streamline/workflows), you can configure the token with the `Reader` role.
* `20220603` as the API version

### Configure the integration in Cortex

1. In Cortex, navigate to the [LaunchDarkly settings page](https://app.getcortexapp.com/admin/integrations/launchdarkly):
   * Click **Integrations** from the main nav. Search for and select **LaunchDarkly**.
2. Click **Add configuration**.
3. Configure the integration details:
   * **Account alias**: Enter the alias for this configuration.
   * **Access token**: Enter your LaunchDarkly access token.
   * **Environment**: Select your environment.
4. Click **Save**.

#### **Configure the integration for multiple LaunchDarkly accounts**[**​**](https://docs.cortex.io/docs/reference/integrations/github#configure-the-integration-for-multiple-propsintegration-accounts)

The LaunchDarkly integration has multi-account support. You can add a configuration for each additional organization, instance, or account by repeating the process above.

Each configuration requires an alias, which Cortex uses to correlate the designated organization, instance, or account with registrations for various entities. Registrations can also use a default configuration without a listed alias. You can edit aliases and default configurations from the LaunchDarkly page in your Cortex settings. Select the edit icon next to a given configuration and toggle **Set as default** on. If you only have one configuration, it will automatically be set as the default.

## How to connect Cortex entities to LaunchDarkly

### Discovery

By default, Cortex will try to "best-guess" the corresponding project in LaunchDarkly based on the key or tags.

Cortex first looks up a LaunchDarkly project using the entity name (e.g. `My Service`), then the entity identifier (e.g. `my-service`). For example, if your entity name is “My Service”, then the corresponding LaunchDarkly project's key or tag should contain either “My Service” or "my-service".

If no project was matched, Cortex will try to "best-guess" feature flags from all available projects using feature flag tags.

### Editing the entity descriptor

You can find the project key and tags in LaunchDarkly under **Account settings > Projects**. The URL for the project will contain the key. For example: `https://app.launchdarkly.com/projects/default/settings/environments`.

If you prefer to use the project tags in the registration instead, you can find it in the projects table or project settings page.

```yaml
x-cortex-launch-darkly:
  projects:
    - key: project-key
      environments: # Optional
        - environmentName: prod
        - environmentName: staging
      alias: alias-1 # alias is optional and only relevant if you have opted into multi account support
    - tag: project-tag
      environments: # Optional
        - environmentName: prod
      alias: alias-2 # alias is optional and only relevant if you have opted into multi account support
  feature-flags:
    - tag: feature-flag-tag
      environments: # Optional
        - environmentName: staging
      alias: alias-3 # alias is optional and only relevant if you have opted into multi account support
```

## Using the LaunchDarkly integration <a href="#still-need-help" id="still-need-help"></a>

### Scorecards and CQL <a href="#still-need-help" id="still-need-help"></a>

With the LaunchDarkly integration, you can create Scorecard rules and write CQL queries based on LaunchDarkly projects.

See more examples in the [CQL explorer](https://app.getcortexapp.com/admin/cql-explorer) in Cortex.

<details>

<summary>Check if LaunchDarkly project is set</summary>

Check if entity has a registered LaunchDarkly project in its [entity descriptor](/ingesting-data-into-cortex/entities-overview/entities#defining-entities-via-yaml-file). If no registration exists, we'll try to automatically detect which corresponding LaunchDarkly project is associated with the entity.

**Definition**: `launchDarkly (==/!=) null`

**Example**

For example, you could write a rule in a Scorecard to check whether an entity has a LaunchDarkly project set:

```
launchDarkly != null
```

</details>

<details>

<summary>Feature flags</summary>

List of flags

**Definition**: `launchDarkly.flags()`

**Example**

In a Scorecard, you could write a rule to check whether an entity has fewer than 10 flags:

```
launchDarkly.flags().length < 10
```

</details>

### View integration logs <a href="#still-need-help" id="still-need-help"></a>

{% hint style="info" %}
This feature is available in Cortex cloud.
{% endhint %}

While viewing an integration's settings page, select the **Logs** tab to view error logs from the last 7 days. You can filter the logs list by configuration and by operation (for example, you could filter to view errors surfaced only via Scorecards).

<div align="left" data-with-frame="true"><figure><img src="/files/x8JmoPqXZTJ7YHeFJpOA" alt="The &#x27;Logs&#x27; tab on an integration&#x27;s settings page shows error information over the past 7 days."><figcaption></figcaption></figure></div>

Click into a row to get more information, including time stamp, status code, full error, and request path.

## FAQs and troubleshooting

#### **How often does the integration poll for new flags?**

A scheduled job runs every 2 hours to check for new flags.

## Still need help?[​](https://docs.cortex.io/docs/reference/integrations/aws#still-need-help) <a href="#still-need-help" id="still-need-help"></a>

The following options are available to get assistance from the Cortex Customer Engineering team:

* **Email**: <help@cortex.io>, or open a support ticket in the in app Resource Center
* **Slack**: Users with a connected Slack channel will have a workflow added to their account. From here, you can either @CortexTechnicalSupport or add a `:ticket:` reaction to a question in Slack, and the team will respond directly.

Don’t have a Slack channel? Talk with your Customer Success Manager.


# Lightstep

{% hint style="info" %}
Cortex connects to many third-party vendors whose system interfaces frequently change. As a result, integration behavior or configuration steps may shift without notice. If you encounter unexpected issues, check with your system administrator or refer to the vendor's documentation for the most current information. Additionally, integration sync times vary and are subject to scheduling overrides and timing variance.
{% endhint %}

### Overview

[ServiceNow Cloud Observability](https://www.servicenow.com/products/observability.html), formerly known as Lightstep, helps you detect changes in your logs, metrics, and traces. Integrate Lightstep with Cortex to drive insights into SLOs and latency and error rate metrics.

### How to configure Lightstep with Cortex

#### Prerequisite

Before getting started, create a [Lightstep API key](https://docs.lightstep.com/docs/create-and-manage-api-keys).

#### Configure the integration in Cortex

1. In Cortex, navigate to the [Lightstep settings page](https://app.getcortexapp.com/admin/integrations/lightstep):
   * Click **Integrations** from the main nav. Search for and select **Lightstep**.
2. Click **Add configuration**.
3. Configure the Lightstep integration form:
   * **Org ID**: Enter your Lightstep organization ID.
     * You can find this in your Lightstep project settings.
   * **Project ID**: Enter the Lightstep project ID.
     * You can find this in your Lightstep project URL, e.g., `https://app.lightstep.com/PROJECT_ID/project`
   * **API key**: Enter the API key you generated in Lightstep.
4. Click **Save**.

### Linking SLOs in Cortex

You can create and manage SLOs by listing relevant latency SLIs through [Streams](https://docs.lightstep.com/docs/monitor-a-service-level-indicator-with-streams). Cortex will pull data from Lightstep, and track against your specified SLO. For example:

```yaml
x-cortex-slos:
  lightstep:
    - streamId: sc4jmdXT
      targets:
        latency:
          - percentile: 0.5
            target: 2
            slo: 0.9995
```

| Field      | Description                                                                                                                   |
| ---------- | ----------------------------------------------------------------------------------------------------------------------------- |
| streamId   | ID of your Lightstep stream, which can be found in Lightstep, through the URL. `https://app.lightstep.com//stream/my-stream/` |
| percentile | Percentile latency for your given streamId, out of 1                                                                          |
| target     | Latency targets in ms. Latency is currently the only target supported                                                         |
| slo        | SLO percentile, out of 1                                                                                                      |

## Using the Lightstep integration

### Entity pages

When an SLO is defined in an entity's descriptor, you'll see detailed data about SLOs in the **Overview** tab.

On the left side of an entity, click **Monitoring > Lightstep** to view the SLO query, target(s), current value for each SLO, a graph of SLO performance over time, and the period of time the SLO is being calculated for. For example, if the time listed is "7 days ago," then the SLO is looking at the time range starting 7 days ago to now.

### Scorecards and CQL

With the Lightstep integration, you can create Scorecard rules and write CQL queries based on Lightstep SLOs.

See more examples in the [CQL Explorer](https://app.getcortexapp.com/admin/cql-explorer) in Cortex.

<details>

<summary>SLOs</summary>

SLOs associated with the entity via ID or tags. You can use this data to check whether an entity has SLOs associated with it, and if those SLOs are passing.

**Definition:** `slos: List<SLO>`

**Example**

In a Scorecard, you can use this expression to make sure an entity is passing its SLOs:

```
slos().all((slo) => slo.passing) == true
```

Use this expression to make sure latency Service Level Indicator (SLI) value is above 99.99%:

```
slos().filter((slo) => slo.name.matchesIn("latency") and slo.sliValue >= 0.9999).length > 0
```

</details>

### View integration logs <a href="#still-need-help" id="still-need-help"></a>

{% hint style="info" %}
This feature is available in Cortex cloud.
{% endhint %}

While viewing an integration's settings page, select the **Logs** tab to view error logs from the last 7 days. You can filter the logs list by configuration and by operation (for example, you could filter to view errors surfaced only via Scorecards).

<div align="left" data-with-frame="true"><figure><img src="/files/x8JmoPqXZTJ7YHeFJpOA" alt="The &#x27;Logs&#x27; tab on an integration&#x27;s settings page shows error information over the past 7 days."><figcaption></figcaption></figure></div>

Click into a row to get more information, including time stamp, status code, full error, and request path.

## Still need help?[​](https://docs.cortex.io/docs/reference/integrations/aws#still-need-help) <a href="#still-need-help" id="still-need-help"></a>

The following options are available to get assistance from the Cortex Customer Engineering team:

* **Email**: <help@cortex.io>, or open a support ticket in the in app Resource Center
* **Slack**: Users with a connected Slack channel will have a workflow added to their account. From here, you can either @CortexTechnicalSupport or add a `:ticket:` reaction to a question in Slack, and the team will respond directly.

Don’t have a Slack channel? Talk with your Customer Success Manager.


# Mend

{% hint style="info" %}
Cortex connects to many third-party vendors whose system interfaces frequently change. As a result, integration behavior or configuration steps may shift without notice. If you encounter unexpected issues, check with your system administrator or refer to the vendor's documentation for the most current information. Additionally, integration sync times vary and are subject to scheduling overrides and timing variance.
{% endhint %}

## Overview

[Mend](https://www.mend.io/) is an automated application security and remediation platform. Integrate Cortex with Mend to drive insights into potential vulnerabilities in your code and your third-party libraries.

Cortex supports integrating with:

* [Mend Static Application Security Testing (SAST)](https://www.mend.io/sast-lp): This product scans for vulnerabilities in the code you write.
* [Mend Software Composition Analysis (SCA)](https://www.mend.io/sca/): This product scans for vulnerabilities in your third-party libraries.

## How to configure Mend with Cortex

See the tabs below for instructions on configuring Mend SAST and Mend SCA.

{% tabs %}
{% tab title="Mend SAST" %}
**Prerequisite**

Before getting started, [create an API token in Mend](https://docs.mend.io/legacy-sast/latest/api-token).

If you're using a self-hosted instance of Mend, you'll need to verify that your Cortex instance is able to reach the Mend instance.\
\
We route our requests through a static IP address. Reach out to support at <help@cortex.io> to receive details about our static IP. If you're unable to directly allowlist our static IP, you can route requests through a secondary proxy in your network that has this IP allowlisted and have that proxy route traffic to your Mend instance.

**Configure the integration in Cortex**

1. In Cortex, navigate to the [Mend settings page](https://app.getcortexapp.com/admin/integrations/mend):
   * Click **Integrations** from the main nav. Search for and select **Mend**.
2. Click **Add configuration**.
3. Configure the Mend SAST integration form:
   * **API token**: Enter the API token you created in Mend.
4. Click **Save**.
   {% endtab %}

{% tab title="Mend SCA" %}
**Prerequisite**

Before getting started, create an [Organization API key](https://docs.mend.io/legacy-sca/latest/global-organization-product-project-api) and a [user key](https://docs.mend.io/legacy-sca/latest/user-level-access-control-in-integrations-and-apis) in Mend.

If you're using a self-hosted instance of Mend, you'll need to verify that your Cortex instance is able to reach the Mend instance.\
\
We route our requests through a static IP address. Reach out to support at <help@cortex.io> to receive details about our static IP. If you're unable to directly allowlist our static IP, you can route requests through a secondary proxy in your network that has this IP allowlisted and have that proxy route traffic to your Mend instance.

**Configure the integration in Cortex**

1. In Cortex, navigate to the [Mend settings page](https://app.getcortexapp.com/admin/settings/mend):
   1. In Cortex, click your avatar in the lower left corner, then click **Settings**.
   2. Under "Integrations", click **Mend**.
2. Click **Add configuration**.
3. Configure the Mend SCA integration form:
   * **Organization type**: Select `Global` or `Single`.
   * **Organization API token**: Enter your Global organization key or a single organization key.
     * This can be found in Mend SCA under the [Integrate tab](https://saas.mend.io/Wss/WSS.html#!adminOrganization_integration).
   * **User key**: Enter your Mend user key.
     * This can be found in Mend under **User profile > User keys**.
   * **URL type**: Select your Mend URL type depending on the server URL for your Mend instance.
     * Select **NEW** if the server URL is `saas.mend.io`.
     * Select **LEGACY** if the server URL is `saas.whitesourcesoftware.com`.
     * Select **CUSTOM** if using a dedicated instance.
   * **Custom URL**: If using a dedicated instance, enter your Mend server URL.
4. Click **Save**.
   {% endtab %}
   {% endtabs %}

### Advanced configuration

If you’re unable to expose your Mend instance to be reachable by Cortex, you can set up a Custom Integration Webhook.

## How to connect Cortex entities to Mend

#### Discovery

By default, Cortex will use your associated Git repository (e.g. `repo-name`) as the "best guess" for the Mend SAST application name and the Mend SCA project name.

If your repository names don’t cleanly match the Mend SAST application names or Mend SCA project names, you can override this in the Cortex Service Descriptor.

#### Editing the entity descriptor

```yaml
x-cortex-static-analysis:
  mend:
    applicationIds:
      - mend_id_1
      - mend_id_2
    projectIds:
      - project_id_1
      - project_id_2
```

The application IDs can be found in the Mend SAST web interface.

A project ID can be found in the Mend SCA web interface; while viewing the project, the ID appears in the URL after `project;id=`.

## Using the Mend integration

### Entity pages

From the **Overview** tab on an entity page, you can find vulnerabilities in the **Code and Security** block.

In the left sidebar of an entity, click **Code & security > Mend** to view the total number of vulnerabilities, a risk score, and a list of vulnerabilities including the risk rating and creation date.

### Scorecards and CQL

With the Mend integration, you can create Scorecard rules and write CQL queries based on Mend projects and applications.

See more examples in the [CQL Explorer](https://app.getcortexapp.com/admin/cql-explorer) in Cortex.

<details>

<summary>Check if Mend project is set</summary>

Check if entity has a registered Mend project

**Definition:** `mend (==/!= null): Boolean`

**Examples**

In a Scorecard, you can write a rule to make sure an entity has a Mend project set:

```
mend != null
```

</details>

<details>

<summary>Vulnerabilities</summary>

List of vulnerabilities, filterable on risk and source

**Definition:** `mend.vulnerabilities(): List`

**Examples**

In a Scorecard, you can write a rule to make sure an entity has fewer than 10 vulnerabilities from both SAST and SCA sources:

```
mend.vulnerabilities(source = ["SAST", "SCA"]).length < 10
```

You can write a rule to make sure an entity has fewer than 3 vulnerabilities with a risk level of "Medium" or "High":

```
mend.vulnerabilities(risk = ["Medium", "High"]).length <= 3
```

</details>

### View integration logs <a href="#still-need-help" id="still-need-help"></a>

{% hint style="info" %}
This feature is available in Cortex cloud.
{% endhint %}

While viewing an integration's settings page, select the **Logs** tab to view error logs from the last 7 days. You can filter the logs list by configuration and by operation (for example, you could filter to view errors surfaced only via Scorecards).

<div align="left" data-with-frame="true"><figure><img src="/files/x8JmoPqXZTJ7YHeFJpOA" alt="The &#x27;Logs&#x27; tab on an integration&#x27;s settings page shows error information over the past 7 days."><figcaption></figcaption></figure></div>

Click into a row to get more information, including time stamp, status code, full error, and request path.

## Still need help?[​](https://docs.cortex.io/docs/reference/integrations/aws#still-need-help) <a href="#still-need-help" id="still-need-help"></a>

The following options are available to get assistance from the Cortex Customer Engineering team:

* **Email**: <help@cortex.io>, or open a support ticket in the in app Resource Center
* **Slack**: Users with a connected Slack channel will have a workflow added to their account. From here, you can either @CortexTechnicalSupport or add a `:ticket:` reaction to a question in Slack, and the team will respond directly.

Don’t have a Slack channel? Talk with your Customer Success Manager.


# Microsoft Teams

{% hint style="info" %}
Cortex connects to many third-party vendors whose system interfaces frequently change. As a result, integration behavior or configuration steps may shift without notice. If you encounter unexpected issues, check with your system administrator or refer to the vendor's documentation for the most current information. Additionally, integration sync times vary and are subject to scheduling overrides and timing variance.
{% endhint %}

[Microsoft Teams](https://www.microsoft.com/en-us/microsoft-teams/group-chat-software) is a communication and collaboration platform designed to promote greater productivity through messaging and file-sharing tools.

Integrating Microsoft Teams with Cortex allows you to:

* Quickly find the relevant MS Teams channel to communicate with the right team, allowing for easier collaboration on projects and faster communication during an incident
  * MS Teams channels appear in the "Owners" block on [entity details pages](/ingesting-data-into-cortex/entities-overview/entities/details).
* Receive actionable [notifications](#managing-microsoft-teams-notifications) directly in MS Teams for Scorecard changes, upcoming Initiatives, weekly summaries of entity performance, and more
* Create [Scorecards](/standardize/scorecards) that enforce standards such as having an MS Teams channel set for projects

## How to configure Microsoft Teams with Cortex

{% hint style="warning" %}
This page describes how to integrate Microsoft Teams with Cortex cloud. If you're using a self-managed Cortex instance, you'll need to follow a manual configuration process to use Cortex's app for Microsoft Teams. Follow the [self-managed Teams guide here](/self-managed/features/integrations/ms-teams).
{% endhint %}

### Step 1: Configure the integration in Cortex

1. In Cortex, navigate to the [Microsoft Teams settings page](https://app.getcortexapp.com/admin/integrations/microsoftteams).
   1. Click **Integrations** from the main nav. Search for and select **Microsoft Teams**.
2. Click **Add configuration**.
3. In the side panel, click **Connect account via Microsoft Teams OAuth**. A popup window will appear.
4. In the pop-up window, follow the prompts to log in to your Microsoft account. The user configuring the integration must accept the delegated permissions listed below:

| Permission                                                                                              | Requirements             | Description                                                  |
| ------------------------------------------------------------------------------------------------------- | ------------------------ | ------------------------------------------------------------ |
| [Get user profile](https://learn.microsoft.com/en-us/graph/api/user-get)                                | `User.Read`              | Read the signed-in user's profile                            |
| [Get users](https://learn.microsoft.com/en-us/graph/api/user-list?view=graph-rest-1.0\&tabs=http)       | `User.ReadBasic.All`     | Pulls Teams users into Cortex                                |
| [Get channels](https://learn.microsoft.com/en-us/graph/api/channel-list?view=graph-rest-1.0\&tabs=http) | `Channel.ReadBasic.All`  | Enables channel connection on entity pages and notifications |
| [Get teams](https://learn.microsoft.com/en-us/graph/api/teams-list?view=graph-rest-1.0\&tabs=http)      | `Team.ReadBasic.All`     | Enables notifications to teams                               |
| [Get channel members](https://learn.microsoft.com/en-us/graph/api/team-list-members)                    | `ChannelMember.Read.All` | Enables Scorecard rule for Teams                             |

After authenticating, you will be redirected to the Microsoft Teams integration settings page in Cortex. In the upper right corner of the page, click **Test configuration** to ensure Microsoft Teams was configured properly.

### Step 2: Install the Cortex app for Teams through Microsoft AppSource

1. On the [Microsoft Teams settings page](https://app.getcortexapp.com/admin/settings/microsoftteams) in Cortex, click the [Microsoft AppSource](https://appsource.microsoft.com/en-us/product/teams-app/WA200005959) link.
2. In AppSource, click **Get it now**. You will be redirected to a page where you can choose whether to download a desktop app or use the web app.

### Step 3: Configure a setup policy for Cortex in Teams

MS Teams admins can configure a setup policy for Cortex, can choose whether to automatically download the Cortex app into the personal Teams environments for users, and can choose to pin the app to make it more easily accessible.

If admins do not add a policy to install the Cortex app, then users will need to download the app during setup.

1. Navigate to the Teams [admin center](https://admin.teams.microsoft.com/) under **Teams app > Setup policies**.
2. Click **Add** to start configuring a setup policy for the Cortex app.
3. After configuring a policy, navigate to the **Installed apps** section. Add the Cortex app here.
   * This will automatically download the app in users' personal Teams environments.
   * MS Teams admins can also apply the policy to specific users in the Teams admin center under **Users > Manage Users**.
4. To pin the app, follow [Microsoft's instructions on pinning apps](https://learn.microsoft.com/en-us/microsoftteams/teams-app-setup-policies#pin-apps).

### Limitations

Cortex does not automatically discover MS Teams channels based on a [Cortex tag](/ingesting-data-into-cortex/entities-overview/entities#cortex-tag) so you must [define channels for each entity](#editing-the-entity-descriptor) as described below.

## How to connect Cortex entities to Microsoft Teams

In order to use this integration's functionality, your MS Teams channels need to be associated with entities in Cortex. Cortex does not automatically discover channels for MS Teams, so you must define them in the [entity descriptor](#editing-the-entity-descriptor).

### Editing the entity descriptor

To associate a Microsoft Teams channel with an entity, define a `x-cortex-microsoft-teams` block in an [entity descriptor](/ingesting-data-into-cortex/entities-overview/entities#defining-entities-via-yaml-file) as shown in the example below.

Defining a Teams channel will provide [direct access to the channel via the entity page](#viewing-microsoft-teams-information-across-cortex) in Cortex.

```yaml
x-cortex-microsoft-teams:
    channels:
    - name: team-engineering
      teamName: engineering
      description: This is a description for the engineering channel in Teams.
      notificationsEnabled: true
```

| Field                  | Description                                    | Required |
| ---------------------- | ---------------------------------------------- | :------: |
| `name`                 | Microsoft Teams channel name **(exact match)** |   **✓**  |
| `teamName`             | Team name **(exact match)**                    |   **✓**  |
| `description`          | Description for the Teams channel              |          |
| `notificationsEnabled` | Boolean to enable/disable notifications        |          |

## Using the Microsoft Teams integration

### Viewing Microsoft Teams information across Cortex

* [Entity details page](/ingesting-data-into-cortex/entities-overview/entities/details): After MS Teams channels are defined in an entity's YAML, MS Teams channels will appear at the top of an entity's overview page in the **MST channels** block. Channels are also listed in the "Owners" page in an entity's sidebar. You can click any channel name to go directly to that channel in Microsoft Teams.\\

  <figure><img src="/files/lCD6qMSOOtSyhbOQoiCz" alt="The MS Teams channels appear in the upper right side of an entity details page."><figcaption></figcaption></figure>
* You can write CQL queries and Scorecard rules based on Microsoft Teams channels. Learn more under [Scorecards and CQL](#scorecards-and-cql).

### Managing Microsoft Teams notifications

After configuring the Microsoft Teams integration, you can choose whether to allow Microsoft Teams notifications for your workspace.

<div align="left"><figure><img src="/files/eAMit5OC0eMiWaWD2jOW" alt="A notification in MS Teams includes actionable information." width="563"><figcaption></figcaption></figure></div>

In Cortex under **Settings > Notifications**, an admin or a user with the `Configure workspace notification settings` permission can enable or disable the option to receive notifications via MS Teams for each type of notification. Users can also adjust their [personal notification settings](/configure/settings/notifications#adjusting-your-personal-notification-subscriptions) to control which notifications they receive via MS Teams.

#### Team, user, and entity MS Teams notifications

Notifications are [user-based, team-based, or entity-based](/configure/settings/notifications#enable-notifications-for-users-teams-and-entities). DMs and channel notifications are sent from the Cortex app.

* User-based notifications are sent to users via a DM from the Cortex app.
* Team-based notifications are sent to the MS Teams channel associated with a team.
* Entity-based notifications are sent to the MS Teams channel associated with an entity.

Learn more about notifications in the [Notifications docs](/configure/settings/notifications).

### Scorecards and CQL

With the Microsoft Teams integration, you can create Scorecard rules and write CQL queries based on Microsoft Teams channels.

See more examples in the [CQL Explorer](https://app.getcortexapp.com/admin/cql-explorer) in Cortex.

<details>

<summary>Check if Microsoft Teams channel is set</summary>

Checks if a given entity has a registered Teams channel in its entity descriptor.

**Definition:** `microsoftTeams (==/!=) null`

Example

For a Scorecard focused on team operations, you can make sure that each team entity has registered a Microsoft Teams channel:

```
microsoftTeams != null
```

</details>

<details>

<summary>Number of Microsoft Teams channels</summary>

Counts the number of Microsoft Teams channels for a given entity.

* Channel name
* Team name

**Definition**: `microsoftTeams.channels().length`

Example

You can use this expression in the Query builder to identify teams missing a Microsoft Teams channel:

```
microsoftTeams.channels().length < 1
```

</details>

<details>

<summary>Total number of members across Microsoft Teams channels registered for the entity</summary>

Counts the total number of members across all Microsoft Teams channels registered for a given entity.

* Channel name
* Member name
* Team name

**Definition:** `microsoftTeams.members().length`

Example

For a Scorecard focused on team operations, you can verify that the Microsoft Teams channel has at least one member in it:

```
microsoftTeams.members().length > 0
```

</details>

### View integration logs <a href="#still-need-help" id="still-need-help"></a>

{% hint style="info" %}
This feature is available in Cortex cloud.
{% endhint %}

While viewing an integration's settings page, select the **Logs** tab to view error logs from the last 7 days. You can filter the logs list by configuration and by operation (for example, you could filter to view errors surfaced only via Scorecards).

<div align="left" data-with-frame="true"><figure><img src="/files/x8JmoPqXZTJ7YHeFJpOA" alt="The &#x27;Logs&#x27; tab on an integration&#x27;s settings page shows error information over the past 7 days."><figcaption></figcaption></figure></div>

Click into a row to get more information, including time stamp, status code, full error, and request path.

## Privacy Policy

We will retain basic Microsoft Teams metadata like user IDs for the period necessary to fulfill the purposes outlined in our [Privacy Policy](https://www.cortex.io/legal/privacy-policy) unless a longer retention period is required or permitted by law, or where the Customer Agreement requires or permits specific retention or deletion periods.

## Still need help?[​](https://docs.cortex.io/docs/reference/integrations/aws#still-need-help) <a href="#still-need-help" id="still-need-help"></a>

The following options are available to get assistance from the Cortex Customer Engineering team:

* **Email**: <help@cortex.io>, or open a support ticket in the in app Resource Center
* **Slack**: Users with a connected Slack channel will have a workflow added to their account. From here, you can either @CortexTechnicalSupport or add a `:ticket:` reaction to a question in Slack, and the team will respond directly.

Don’t have a Slack channel? Talk with your Customer Success Manager.


# New Relic

{% hint style="info" %}
Cortex connects to many third-party vendors whose system interfaces frequently change. As a result, integration behavior or configuration steps may shift without notice. If you encounter unexpected issues, check with your system administrator or refer to the vendor's documentation for the most current information. Additionally, integration sync times vary and are subject to scheduling overrides and timing variance.
{% endhint %}

[New Relic](https://newrelic.com/) is a performance tracking and analytics tool that helps engineers gain visibility into their software. Integrating New Relic with Cortex allows you to:

* Discover entities and track ownership
* View SLO and monitoring information on entity pages in Cortex
* Embed New Relic dashboards on entity pages in Cortex
* Create Scorecards to drive alignment on projects involving New Relic metrics

## How to configure New Relic with Cortex

### Prerequisite

Before getting started:

* As a full platform user in New Relic, create a [New Relic user key](https://docs.newrelic.com/docs/apis/intro-apis/new-relic-api-keys/#user-key).
  * New Relic user keys are linked to the account they were created from, so if this account is ever deleted, the integration with Cortex will stop working.

### Configure the integration in Cortex

1. In Cortex, navigate to the [New Relic settings page](https://app.getcortexapp.com/admin/integrations/newrelic):
   1. Click **Integrations** from the main nav. Search for and select **New Relic**.
2. Click **Add configuration**.
3. Configure the New Relic integration form:
   * **Account alias:** Enter a name for this account.
   * **Personal key:** Enter the user key you generated in New Relic.
   * **Account ID:** Enter the [ID for the account](https://docs.newrelic.com/docs/accounts/accounts-billing/account-structure/account-id/) that the user key was generated with.
   * **Use EU region:** Optionally enable this toggle to use the EU region of New Relic.
4. Click **Save**.

Once you save your configuration, you'll see it listed on the integration's settings page in Cortex. If you’ve set everything up correctly, you’ll see the option to **Remove Integration** in Settings.

You can also use the **Test all configurations** button to confirm that the configuration was successful. If your configuration is valid, you’ll see a banner that says “Configuration is valid. If you see issues, please see documentation or reach out to Cortex support.”

#### Cross-account access

After setting up the integration, you will be redirected to the [New Relic settings page](https://app.getcortexapp.com/admin/settings/newrelic) where you can enable the cross-account access feature. If you have an account that supports subordinate accounts, you can enable this setting to fetch applications and SLOs for all the accounts that are under the configured one.

### **Configure the integration for multiple New Relic accounts**[**​**](https://docs.cortex.io/docs/reference/integrations/newrelic#configure-the-integration-for-multiple-propsintegration-accounts)

The New Relic integration has multi-account support. You can add a configuration for each additional by repeating the process above.

Each configuration requires an alias, which Cortex uses to correlate the designated with registrations for various entities. Registrations can also use a default configuration without a listed alias. You can edit aliases and default configurations from the New Relic page in your Cortex settings. Select the edit icon next to a given configuration and toggle **Set as default** on. If you only have one configuration, it will automatically be set as the default.

## How to connect Cortex entities to New Relic

#### Auto discovery

There are two ways to auto-map New Relic applications and services to Cortex entities:

* By default, Cortex will use the [Cortex tag](/ingesting-data-into-cortex/entities-overview/entities#cortex-tag) (e.g. `my-entity`) or its name as the "best guess" for New Relic applications. For example, if your Cortex tag is `my-entity`, then the corresponding application in New Relic should also be `my-entity`. The name is not case-sensitive.
  * If your New Relic applications don’t cleanly match the Cortex tag or name, you can override this in the Cortex entity descriptor.
* Cortex also supports mapping New Relic applications to Cortex entities via New Relic tagKeys. By default, a Cortex entity will be mapped to a New Relic application or service with New Relic tag key = "service" and tag value = the service's Cortex tag.
  * You can customize the tag key names on the [New Relic settings page](https://app.getcortexapp.com/admin/settings/newrelic) in Cortex.

**Note:** Cortex does not support auto-mapping of SLOs. SLOs have to be defined via the entity YAML or attached to a mapped application or service.

**Dependencies**

Cortex automatically maps dependencies between your entities by utilizing New Relic's [Service Map](https://docs.newrelic.com/docs/new-relic-solutions/new-relic-one/ui-data/service-maps/service-maps/) data.

Say you have two applications in NewRelic (Application A and Application B), and in the service map Application A calls Application B. In Cortex you have two Entities (Cortex Entity A and Cortex Entity B), where Cortex Entity A is mapped to New Relic Application A and Cortex Entity B is mapped to New Relic Application B. Cortex will take the mapped relationship from Application A to Application B and create a dependency from Cortex Entity A to Cortex Entity B.

### Import entities from New Relic

See the [Create services documentation](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/add-services#creating-services) for instructions on importing entities.

### Editing the entity descriptor

**APM services**

New Relic application metrics can be fetched for each entity using application IDs or tags.

```yaml
x-cortex-apm:
  newrelic:
    applications:
    - applicationId: 1234567
      alias: Default-App
    - applicationId: 8904321
      alias: Another-App
```

While the `applications` wrapper format is the recommended format, Cortex also supports a flat array:

```yaml
x-cortex-apm:
  newrelic:
    - applicationId: 1234567
```

| Field           | Description                                                                                      | Required |
| --------------- | ------------------------------------------------------------------------------------------------ | :------: |
| `applications`  | Specifies that the APM service should be found by application ID                                 |   **✓**  |
| `applicationID` | ID for the application that the service belongs to                                               |   **✓**  |
| `alias`         | Alias for the configuration in Cortex (only needed if you have opted into multi-account support) |          |

```yaml
x-cortex-apm:
  newrelic:
    tags:
    - tag: tagKey
      value: tagValue
      alias: Default-App
```

| Field   | Description                                                                                      | Required |
| ------- | ------------------------------------------------------------------------------------------------ | :------: |
| `tags`  | Specifies that the APM service should be found by tag                                            |   **✓**  |
| `tag`   | Tag key for the APM service(s)                                                                   |   **✓**  |
| `value` | Tag value for the APM service(s)                                                                 |   **✓**  |
| `alias` | Alias for the configuration in Cortex (only needed if you have opted into multi-account support) |          |

Instructions to find your Application ID can be found in the [New Relic docs](https://docs.newrelic.com/docs/apis/rest-api-v2/get-started/get-app-other-ids-new-relic-one). You can also find the Application ID in the URL in New Relic.

You can also find information on finding and managing tags in the [New Relic docs](https://docs.newrelic.com/docs/new-relic-solutions/new-relic-one/core-concepts/use-tags-help-organize-find-your-data/#filter-tags).

**OpenTelemetry**

[OpenTelemetry](https://opentelemetry.io/) services can be associated with the entity only using tags. For this type of service New Relic doesn't generate application ID.

```yaml
x-cortex-apm:
  newrelic:
    tags:
    - tag: tagKey
      value: tagValue
      alias: Default-App
```

| Field   | Description                                                                                      | Required |
| ------- | ------------------------------------------------------------------------------------------------ | :------: |
| `tags`  | Specifies that the OpenTelemetry service should be found by tag                                  |   **✓**  |
| `tag`   | Tag key for the APM service(s)                                                                   |   **✓**  |
| `value` | Tag value for the APM service(s)                                                                 |   **✓**  |
| `alias` | Alias for the configuration in Cortex (only needed if you have opted into multi-account support) |          |

Cortex fetches OpenTelemetry data every 5 minutes, but the data refresh may take longer depending on how much data you have.

**Embeds**

Cortex can also embed dashboards from New Relic.

```yaml
x-cortex-dashboards:
  embeds:
    - type: newrelic
      url: https://chart-embed.service.newrelic.com/example/1a234bc5-d6e7-890f-g123-456h7ij8901 
```

| Field  | Description                                                                                                                                              | Required |
| ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------- | :------: |
| `type` | Specifies the source of the embed; in this case, should be `newrelic`                                                                                    |   **✓**  |
| `url`  | URL for the dashboard. It must be publicly accessible, or if you can access the iFrame via VPN, it should be accessible in Cortex while also on the VPN. |   **✓**  |

Learn more about embedding charts in the [Adding external docs](/ingesting-data-into-cortex/entities-overview/entities/external-docs) page.

**SLOs**

SLO can be fetched for each entity using New Relic entity GUID for respective SLO or associated service. Detailed instructions how to obtain entity GUID can be found in [New Relic docs](https://docs.newrelic.com/docs/new-relic-solutions/new-relic-one/core-concepts/what-entity-new-relic/#find).

Fetched SLO information can be found in the `Operations` and `Integrations` sections of an entity page.

```yaml
x-cortex-slos:
  newrelic:
    - id: MjU5ODYxOXxFWFR8U0VSVklDRV9MRVZFTHiw0TI5ODQ
      alias: my-default-alias
    - id: MjU5ODYxOXxFWFR8U0VSVklDRV9MRVZFTHiw0TI76QB
      alias: my-other-alias
    - id: MjU5ODYxOXxFWFRAB6VSVklDRV9MRVZFTHiw0TI76QD
```

| Field   | Description                                                                                                                                                     | Required |
| ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------: |
| `id`    | New Relic entity guid for the SLO or the associated service; if you use the GUID for a parent service, all SLOs associated with it will be imported into Cortex |   true   |
| `alias` | Alias for the configuration in Cortex (only needed if you have opted into multi-account support)                                                                |          |

If the alias is not specified, like with the third ID above, Cortex will use the default configuration.

If you use the GUID for a parent service to define the SLOs for a given entity, Cortex will import all SLOs associated with that service.

## Using the New Relic integration

### View New Relic data on entity pages

When entities are tied to New Relic, SLO and monitoring information appear under the Monitoring section on the overview of the [entity details page](/ingesting-data-into-cortex/entities-overview/entities/details).

More data is available under the **Monitoring** page in the entity's sidebar:

* Throughput
* Response time
* Error rate
* Apdex target
* Apdex score
* Host count
* Instance count
* Concurrent instance count

In the SLOs section, you'll be able to see a list of all SLOs tied to that entity, the target and current SLO score, and the period of time the SLO is being calculated for. For example, if the time listed is "7 days ago," then the SLO is looking at the time range starting 7 days ago to now\..

The SLO name will display in green when passing and orange when failing.

If you've defined [dashboards](/ingesting-data-into-cortex/entities-overview/entities/external-docs#embedded-dashboards) in an entity's YAML, you'll be able to view the graphs from an entity's details page. Open the **Dashboard** page in the entity's sidebar. All dashboards defined in the descriptor will be embedded on this page.

New Relic dashboards must be defined individually for each entity.

### Relationship graphs

[Dependencies](#dependencies) detected from New Relic will appear in [Relationship graphs](/ingesting-data-into-cortex/entities-overview/entities/relationship-graph). You can [manually sync dependencies](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/dependencies#sync-dependencies) in the Relationship Graph.

### Scorecards and CQL

With the New Relic integration, you can create Scorecard rules and write CQL queries based on New Relic performance metrics.

See more examples in the [CQL Explorer](https://app.getcortexapp.com/admin/cql-explorer) in Cortex.

<details>

<summary>Application summary</summary>

Fetch high-level [summary data](https://docs.newrelic.com/docs/apis/rest-api-v2/application-examples-v2/summary-data-examples-v2) for a given New Relic application.

This expression enables you to score entities on reliability metrics:

* Apdex score
* Apdex target
* Concurrent stance count
* Error rate
* GUID
* Host count
* ID
* Instance count
* Name
* Response time
* Throughput
* Type

**If there is not an application ID set in the entity descriptor, a Scorecard rule based on this expression will fail.**

**Definition:** `newrelic.applications()`

**Example**

You can use this expression in a Scorecard rule to make sure entities' Apdex score is at least 0.9:

```
newrelic.applications().all(application) => application.apdexScore >= 0.9
```

</details>

<details>

<summary>New Relic application is set</summary>

Check if entity has a New Relic application ID set in its entity descriptor.

This can be a good companion to other rules that will fail without a defined application ID, like `newrelic.applications()`.

**Definition:** `newrelic (==/!=) null`

**Example**

You can use this expression in an onboarding Scorecard to make sure that entities have a New Relic application ID set:

```
newrelic != null
```

</details>

<details>

<summary>Raw NRQL query</summary>

Execute an arbitrary NRQL query and capture the [raw JSON back out](https://api.newrelic.com/docs/).

This expression is not inherently tied to a single entity and requires a custom query to pull the specific data what you need. The raw JSON can be parsed using JQ or [Open Policy Agent](https://www.openpolicyagent.org/docs/v0.52.0/) language.

**Definition:** `newrelic.rawNrql(query: Text)`

**Examples**

You can use this expression in a Scorecard measuring performance to make sure that the 95th percentile of latency has been less than 500ms in the last 3 weeks for a given entity:

```
jq(newrelic.rawNrql("SELECT percentile(duration) FROM PageView WHERE = '" + newrelic.applications().firstOrNull().name + "' SINCE 3 weeks ago COMPARE WITH 1 week AGO TIMESERIES AUTO"), "[.[].\"percentile.duration\".\"95\"] | add / length") < 500
```

Or you can use this expression in a CQL report to read the timeseries of the `process.cpu.usage` metric for the last 30 minutes using NRQL and a New Relic service GUID:

```
newrelic.rawNrql("SELECT latest(`process.cpu.usage`) FROM Metric WHERE `entity.guid` = '"+newrelic.applications().getOrNull(0)?.guid+"' SINCE 30 MINUTES AGO TIMESERIES")
```

</details>

<details>

<summary>SLOs</summary>

SLOs associated with the entity via ID or tags. You can use this data to check whether an entity has SLOs associated with it and if those SLOs are passing.

SLOs

* History
* ID
* Name
* Operation
* Remaining budget
* SLI value
* SLO target
* Source
* Thresholds

SLO datum (timeseries data for the SLI)

* Datum
* Ts

Named threshold (SLOs thresholds like "warning" or "error" states)

* Name
* Threshold

**Definition:** `slos`

**Examples**

You can use SLO data from New Relic to evaluate entities in Scorecards. For an onboarding Scorecard, you can make sure that entities have at least 1 SLO defined:

```
slos().length > 0
```

For a project standards Scorecard, you can also use this expression to make sure entities are passing all of their SLOs:

```
slos().all((slo) => slo.passing) == true
```

</details>

**OpenTelemetry metrics**

OpenTelemetry metrics available in the [New Relic Metrics Exlorer](https://docs.newrelic.com/docs/query-your-data/explore-query-data/browse-data/introduction-data-explorer/) can be accessed or manipulated for a given entity by combining CQL and [NRQL](https://docs.newrelic.com/docs/nrql/nrql-syntax-clauses-functions/) native query.

<details>

<summary>Accessing OpenTelemetry data with CQL and NRQL</summary>

In Cortex, you can access OpenTelemetry data by incorporating a raw NRQL query into this CQL expression with the associated [New Relic GUID](https://docs.newrelic.com/docs/new-relic-solutions/new-relic-one/core-concepts/what-entity-new-relic/#find).

**Definition:** `newrelic.applications().getOrNull(0)?.guid`

**Example**

You can execute raw NRQL query to collect average `http.server.requests` in a CQL report:

```
newrelic.rawNrql("SELECT average(`http.server.requests`) FROM Metric WHERE `entity.guid` = '"+newrelic.applications().getOrNull(0)?.guid+"' SINCE 7 DAYS AGO")
```

</details>

### View integration logs <a href="#still-need-help" id="still-need-help"></a>

{% hint style="info" %}
This feature is available in Cortex cloud.
{% endhint %}

While viewing an integration's settings page, select the **Logs** tab to view error logs from the last 7 days. You can filter the logs list by configuration and by operation (for example, you could filter to view errors surfaced only via Scorecards).

<div align="left" data-with-frame="true"><figure><img src="/files/x8JmoPqXZTJ7YHeFJpOA" alt="The &#x27;Logs&#x27; tab on an integration&#x27;s settings page shows error information over the past 7 days."><figcaption></figcaption></figure></div>

Click into a row to get more information, including time stamp, status code, full error, and request path.

## Still need help?[​](https://docs.cortex.io/docs/reference/integrations/aws#still-need-help) <a href="#still-need-help" id="still-need-help"></a>

The following options are available to get assistance from the Cortex Customer Engineering team:

* **Email**: <help@cortex.io>, or open a support ticket in the in app Resource Center
* **Slack**: Users with a connected Slack channel will have a workflow added to their account. From here, you can either @CortexTechnicalSupport or add a `:ticket:` reaction to a question in Slack, and the team will respond directly.

Don’t have a Slack channel? Talk with your Customer Success Manager.


# Okta

{% hint style="info" %}
Cortex connects to many third-party vendors whose system interfaces frequently change. As a result, integration behavior or configuration steps may shift without notice. If you encounter unexpected issues, check with your system administrator or refer to the vendor's documentation for the most current information. Additionally, integration sync times vary and are subject to scheduling overrides and timing variance.
{% endhint %}

## Overview

[Okta](https://www.okta.com/) is an identity and access management (IAM) platform. Integrate Cortex with Okta to drive insights into authentication and ownership.

After configuring the integration, you can set Okta teams and team members as owners of entities.

For information on configuring Okta SSO or Okta SCIM for logging in to Cortex, see the [Okta SSO documentation](/configure/settings/managing-users/configuring-sso) and [Okta SCIM documentation](/configure/settings/managing-users/provisioning-users-with-scim/okta-scim).

## How to configure Okta with Cortex

### Prerequisites

Before getting started:

* An Okta administrator, with at least the [View groups](https://help.okta.com/en-us/Content/Topics/Security/custom-admin-role/about-role-permissions.htm) permissions, must [create an Okta API token](https://developer.okta.com/docs/guides/create-an-api-token/create-the-token/).
  * Grant the following scopes for the API token:
    * `okta.groups.read`
    * `okta.profileMappings.read`
    * `okta.users.read`
* Obtain your Okta domain.
  * This can be found in the prefix of your Okta URL. For example, `https://domain.okta.com`.

### Configure the integration in Cortex

1. In Cortex, navigate to the [Okta settings page](https://app.getcortexapp.com/admin/integrations/okta):
   * Click **Integrations** from the main nav. Search for and select **Okta**.
2. Click **Add configuration**.
3. Configure the Okta integration form:
   * **Domain**: Enter your Okta domain.
   * **API token**: Enter your Okta API token.
   * **Group types**: Specify which group types to include.
4. Click **Save**.

## How to connect Cortex entities to Okta

### Import teams from Okta

See the [Create teams documentation](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/teams#creating-a-team) for instructions on importing entities.

Team data syncs from Okta daily at 3 p.m. UTC.

### Editing the entity descriptor

```yaml
x-cortex-owners:
  - type: group
    name: Engineering # group name in Okta
    provider: OKTA
    description: This is a description for this owner # optional
```

The group name is case-sensitive and should be exactly the same as in Okta.

## Using the Okta integration

### Scorecards and CQL

With the Okta integration, you can create Scorecard rules and write CQL queries based on Okta teams.

See more examples in the [CQL Explorer](https://app.getcortexapp.com/admin/cql-explorer) in Cortex.

<details>

<summary>All ownership details</summary>

A special built-in type that supports a null check or a count check, used to enforce ownership of entities.

**Definition:** `ownership: Ownership | Null`

**Example**

An initial level in a security Scorecard might include a rule to ensure an entity has at least one team as an owner:

```
ownership.teams().length > 0
```

</details>

<details>

<summary>All owner details</summary>

List of owners, including team members and individual users, for each entity

**Definition:** `ownership.allOwners()`

**Example**

The Scorecard might include a rule to ensure that entity owners all have an email set:

```
ownership.allOwners().all((member) => member.email != null)
```

</details>

<details>

<summary>Team details</summary>

List of teams for each entity

**Definition:** `ownership.teams(): List<Team>`

**Example**

The Scorecard might include a rule to ensure that an entity owners all have a description and are not archived:

```
ownership.teams().all(team => team.description != null and team.isArchived == false)
```

</details>

### View integration logs <a href="#still-need-help" id="still-need-help"></a>

{% hint style="info" %}
This feature is available in Cortex cloud.
{% endhint %}

While viewing an integration's settings page, select the **Logs** tab to view error logs from the last 7 days. You can filter the logs list by configuration and by operation (for example, you could filter to view errors surfaced only via Scorecards).

<div align="left" data-with-frame="true"><figure><img src="/files/x8JmoPqXZTJ7YHeFJpOA" alt="The &#x27;Logs&#x27; tab on an integration&#x27;s settings page shows error information over the past 7 days."><figcaption></figcaption></figure></div>

Click into a row to get more information, including time stamp, status code, full error, and request path.

## Background sync

Cortex conducts an ownership sync for Okta teams every day at 3 p.m. UTC.

## Troubleshooting and FAQ

**I've added an API token but the login is still using Google.**

To set up Okta for SSO, use the [Okta SSO guide](/configure/settings/managing-users/configuring-sso/okta).

## Still need help?[​](https://docs.cortex.io/docs/reference/integrations/aws#still-need-help) <a href="#still-need-help" id="still-need-help"></a>

The following options are available to get assistance from the Cortex Customer Engineering team:

* **Email**: <help@cortex.io>, or open a support ticket in the in app Resource Center
* **Slack**: Users with a connected Slack channel will have a workflow added to their account. From here, you can either @CortexTechnicalSupport or add a `:ticket:` reaction to a question in Slack, and the team will respond directly.

Don’t have a Slack channel? Talk with your Customer Success Manager.


# Opsgenie

{% hint style="info" %}
Cortex connects to many third-party vendors whose system interfaces frequently change. As a result, integration behavior or configuration steps may shift without notice. If you encounter unexpected issues, check with your system administrator or refer to the vendor's documentation for the most current information. Additionally, integration sync times vary and are subject to scheduling overrides and timing variance.
{% endhint %}

{% hint style="danger" %}
Atlassian is deprecating the Opsgenie product and encouraging their customers to migrate to Jira Service Management. Read more about moving from Opsgenie to Jira Service Management on [Atlassian's web site](https://support.atlassian.com/jira-service-management-cloud/docs/start-shifting-from-opsgenie-to-jira-service-management/).

Cortex is actively working on developing an integration with Jira Service Management.
{% endhint %}

[Opsgenie](https://www.atlassian.com/software/opsgenie) is an alert and on-call management platform from Atlassian.

Integrating Opsgenie with Cortex allows you to:

* Pull in on-call rotation data and escalation policies
  * The on-call user or team will appear in the **Current On-call** block on an entity's details page.
  * You can also view on-call information on an entity page in its side panel under **Integrations > On-call**.
* View alerts from Opsgenie in an entity's event timeline
* Create [Scorecards](#scorecards-and-cql) that track progress and drive alignment on projects involving your on-call schedules and alerts

## How to configure Opsgenie with Cortex

### Prerequisite

Before getting started, create an [Opsgenie API key](https://support.atlassian.com/opsgenie/docs/api-key-management/) with the following permissions:

* `Read`
* `Configuration Access`

### Configure the integration in Cortex

1. In Cortex, navigate to the [Opsgenie settings page](https://app.getcortexapp.com/admin/integrations/opsgenie):
   * Click **Integrations** from the main nav. Search for and select **Opsgenie**.
2. Configure the Opsgenie integration form:
   * **Subdomain**: Enter the subdomain assigned to your Opsgenie instance.
   * **API key**: Enter your Opsgenie API key.
   * **Use European service region**: Optionally, toggle this setting on to enable the EU region of Opsgenie.
3. Click **Save**.

## How to connect Cortex entities to Opsgenie

### Discovery

By default, Cortex will use the [Cortex tag](/ingesting-data-into-cortex/entities-overview/entities#cortex-tag) (e.g. `my-entity`) as the "best guess" value for the `backend` and `service` tags on your alerts. For example, if your alert in Opsgenie has the tag `backend:my-entity`, the alert will be automatically associated with the entity in Cortex with a unique identifier of `my-entity`.

If your Opsgenie tags don’t cleanly match the Cortex tag, or you use different identifying tags, you can override this in the Cortex entity descriptor.

### Entity descriptor

```yaml
x-cortex-alerts:
  - type: opsgenie
    tag: different-tag
    value: my-entity-override-tag
```

| Field   | Description                                       | Required |
| ------- | ------------------------------------------------- | :------: |
| `type`  | Type of alert (in this case, `opsgenie`)          |   **✓**  |
| `tag`   | Type of tag in Opsgenie (e.g. `backend`)          |   **✓**  |
| `value` | Alert in Opsgenie (e.g. `my-entity-override-tag`) |   **✓**  |

For example, for the tag `different-tag:my-entity-override-tag`, the entity descriptor would have `different-tag` in the **tag** field and `my-entity-override-tag` in the **value** field.

You can add a list of tags to use for lookup. Cortex will use an `OR` operator when querying Opsgenie (e.g. `backend:my-entity OR service:another-value`).

The `value` field also supports wildcards (e.g. `value: my-entity*`).

**Adding a schedule**

You can define the following block in an entity descriptor to add an Opsgenie schedule. Cortex supports adding a schedule by ID or UUID. You can add one schedule per entity.

The UUID for the schedule can be found in URL when viewing schedule details by clicking on the schedule name under who is on-call.

```yaml
x-cortex-oncall:
  opsgenie:
    type: SCHEDULE
    id: Cortex-Engineering
```

| Field  | Description                                               | Required |
| ------ | --------------------------------------------------------- | :------: |
| `type` | Opsgenie component being added (in this case, `SCHEDULE`) |   **✓**  |
| `id`   | Schedule ID or UUID                                       |   **✓**  |

#### Ownership

```yaml
x-cortex-owners:
  - type: group
    name: My Opsgenie Team
    provider: OPSGENIE
    description: This is a description for this owner
```

| Field         | Description                                               | Required |
| ------------- | --------------------------------------------------------- | :------: |
| `type`        | Ownership type (in this case, `group`)                    |   **✓**  |
| `name`        | Name of the team defined in Opsgenie (\*\*case-sensitive) |   **✓**  |
| `provider`    | Identity provider (in this case, `OPSGENIE`)              |   **✓**  |
| `description` | Description for the team, to be displayed in Cortex       |          |

#### Identity mappings

Cortex maps email addresses in your Opsgenie instance to email addresses that belong to team members in Cortex. When identity mapping is set up, users will be able to see their personal on-call status from the developer homepage.

## Using the Opsgenie integration

After setting up the integration, Opsgenie information will appear in several places across Cortex.

### Viewing on-call information for an entity

On an [entity details page](/ingesting-data-into-cortex/entities-overview/entities/details), current on-call information from Opsgenie will display in the **On-call** block.

Escalation policy, the level associated with the policy, and other on-call information will also appear in the entity's sidebar in the "On-call & incidents" page. Owners assigned to each level will also be hyperlinked to the user or team page in Opsgenie.

<figure><img src="/files/grNpdDVStmd2gyI9b7Qj" alt="On-call information appears on the right side of an entity details page."><figcaption></figcaption></figure>

### Viewing recent Opsgenie events

Click **Events** in an entity's sidebar to view recent events pulled in from Opsgenie.

### Viewing on-call information on the dev homepage

The Opsgenie integration enables Cortex to pull on-call information into the on-call block on the Dev homepage. On-call data from Opsgenie is refreshed every 1 minute.

### Scorecards and CQL

With the Opsgenie integration, you can create Scorecard rules and write CQL queries based on Opsgenie on-call schedules and alerts.

See more examples in the [CQL Explorer](https://app.getcortexapp.com/admin/cql-explorer) in Cortex.

<details>

<summary>Check if on-call is set</summary>

Check if entity has a registered schedule.

**Definition:** `oncall (==/!=) null`

**Example**

For a Scorecard focused an production readiness, you can use this expression to make sure on-call is defined for entities:

```
oncall != null
```

This rule will pass if an entity has an on-call schedule set.

</details>

<details>

<summary>Number of alerts</summary>

Number of alerts for a given lookback period that match a given [search query](https://support.atlassian.com/opsgenie/docs/search-queries-for-alerts/).

**Definition:** `oncall.numOfAlerts(lookback=,query=).length`

**Example**

For a Scorecard focused on maturity or quality, you can use this expression to make sure a given entity has fewer than two alerts in the last month:

```
oncall.numOfAlerts(lookback=duration("P1M"),query="status: open").length < 2
```

You could also refine this rule by specifying priority level:

```
oncall.numOfAlerts(lookback=duration("P1M"),query="priority: P1").length < 2
```

Entities will pass this rule if they have fewer than 2 alerts with priority level "P1" in the last month.

</details>

<details>

<summary>Number of escalations</summary>

Number of escalation tiers in escalation policy.

**Definition:** `oncall.numOfEscalations()`

**Example**

This expression could be used in a Scorecard focused on production readiness or service maturity. For example, you can check that there are at least two tiers in an escalation policy for a given entity, so that if the first on-call does not ack, there is a backup:

```
oncall.numOfEscalations() >= 2
```

While making sure an on-call policy set is a rule that would be defined in a Scorecard's first level, a rule focused on escalation tiers would make more sense in a higher level.

</details>

<details>

<summary>On-call metadata</summary>

On-call metadata.

* ID
* Name
* Type

**Definition:** `oncall.details()`

**Example**

To find all entities without a schedule-type on-call registration, you can use this expression in the Query builder:

```
oncall.details().type =! "schedule"
```

If you're migrating on-call policies, you could use this rule to check for outdated policies. Let's say, for example, all outdated Opsgenie policies start with "Legacy" in their titles.

```
oncall.details().id.matches("Legacy*") == false
```

Entities with on-call policies that start with "Legacy" will fail, while those with other policy names will pass.

</details>

**Ownership CQL**

<details>

<summary>All ownership details</summary>

A special built-in type that supports a null check or a count check, used to enforce ownership of entities.

**Definition:** `ownership: Ownership | Null`

**Example**

An initial level in a security Scorecard might include a rule to ensure an entity has at least one team as an owner:

```
ownership.teams().length > 0
```

</details>

<details>

<summary>All owner details</summary>

List of owners, including team members and individual users, for each entity

**Definition:** `ownership.allOwners()`

**Example**

The Scorecard might include a rule to ensure that entity owners all have an email set:

```
ownership.allOwners().all((member) => member.email != null)
```

</details>

<details>

<summary>Team details</summary>

List of teams for each entity

**Definition:** `ownership.teams(): List<Team>`

**Example**

The Scorecard might include a rule to ensure that an entity owners all have a description and are not archived:

```
ownership.teams().all(team => team.description != null and team.isArchived == false)
```

</details>

### View integration logs <a href="#still-need-help" id="still-need-help"></a>

{% hint style="info" %}
This feature is available in Cortex cloud.
{% endhint %}

While viewing an integration's settings page, select the **Logs** tab to view error logs from the last 7 days. You can filter the logs list by configuration and by operation (for example, you could filter to view errors surfaced only via Scorecards).

<div align="left" data-with-frame="true"><figure><img src="/files/x8JmoPqXZTJ7YHeFJpOA" alt="The &#x27;Logs&#x27; tab on an integration&#x27;s settings page shows error information over the past 7 days."><figcaption></figcaption></figure></div>

Click into a row to get more information, including time stamp, status code, full error, and request path.

## Background sync

Cortex performs the following background jobs:

* **Ownership**: A sync for Opsgenie teams every day at 9 a.m. UTC.
* **Identity mapping**: A sync for Opsgenie identities every day at 10 a.m. UTC.

## Still need help?[​](https://docs.cortex.io/docs/reference/integrations/aws#still-need-help) <a href="#still-need-help" id="still-need-help"></a>

The following options are available to get assistance from the Cortex Customer Engineering team:

* **Email**: <help@cortex.io>, or open a support ticket in the in app Resource Center
* **Slack**: Users with a connected Slack channel will have a workflow added to their account. From here, you can either @CortexTechnicalSupport or add a `:ticket:` reaction to a question in Slack, and the team will respond directly.

Don’t have a Slack channel? Talk with your Customer Success Manager.


# PagerDuty

Configuring the integration for PagerDuty

{% hint style="info" %}
Cortex connects to many third-party vendors whose system interfaces frequently change. As a result, integration behavior or configuration steps may shift without notice. If you encounter unexpected issues, check with your system administrator or refer to the vendor's documentation for the most current information. Additionally, integration sync times vary and are subject to scheduling overrides and timing variance.
{% endhint %}

## Why use the integration for PagerDuty

PagerDuty is an incident response platform for managing alerts, on-call rotations, and escalation policies. The integration for PagerDuty syncs your PagerDuty services, on-call schedules, escalation policies, and incidents into Cortex, connecting each service's operational data to its ownership and metadata in your software catalog.

Instead of switching tools to answer "who is on call for this service?", you can see current on-call information on an entity's details page, view PagerDuty incidents in its event timeline, and trigger incidents without leaving Cortex. When an incident is triggered, the [On-call Assistant](/ingesting-data-into-cortex/entities-overview/entities/oncall-assistant) notifies users via Slack with runbooks, dependencies, and key information about the affected entity. Because PagerDuty data is available in CQL, you can also create Scorecards that enforce on-call standards at scale and track metrics like mean time to resolution (MTTR) in Eng Intelligence.

Integrating PagerDuty with Cortex allows you to:

* Pull in PagerDuty services, on-call schedules, and escalation policies. The on-call user or team appears in the **On-call** block on an entity's metadata sidebar, and on the entity's details page under **Connections > On-call**.
* Trigger incidents in PagerDuty directly from Cortex.
* Automatically surface vital information about entity health and metadata when an incident is triggered, using the On-call Assistant.
* View incidents from PagerDuty in an entity's event timeline.
* View on-call information from PagerDuty on the Engineering homepage.
* Use PagerDuty metrics in Eng Intelligence to gain insight into services, incident response, and more.
* Create Scorecards that track progress and drive alignment on projects involving your on-call schedules and alerts.

## Configuring PagerDuty

### Prerequisites

1. Users with the `Configure Integrations` permission can configure PagerDuty.

### Step 1: Creating an API key in PagerDuty

1. In PagerDuty, go to **Integrations > API Access Keys**.
2. [Create a PagerDuty API key](https://support.pagerduty.com/docs/generating-api-keys).&#x20;
   1. When adding the API key, you have the option to set read or write permissions:
      1. `Read-only` - Enables Cortex to read any and all data from PagerDuty
         1. If you create an API key with `Read-only` permissions, and you want to use the On-call Assistant in Slack, you also need to [configure a webhook](/ingesting-data-into-cortex/entities-overview/entities/oncall-assistant#configuring-a-webhook-for-read-only-api-keys) to get the Assistant working.
      2. `Write` - Allows users to trigger incidents from an entity page in Cortex, and enables the On-call Assistant
3. Copy the API key. Don't skip this step! You'll need the key to complete the setup.

#### A note about Scoped OAuth apps

If you registered a Scoped OAuth app in PagerDuty, you must also grant the following permissions:

* `incident.write` to create incidents
* `escalation_policies.write` to create escalation policies
* `schedules.write` to create schedules
* `services.write` to create services
* `teams.write` to create teams

### Step 2: Installing the PagerDuty integration in Cortex

1. From the main sidebar, select **Integrations**.
2. Locate PagerDuty, then click **Install**. The PagerDuty side panel opens.
3. In the PagerDuty side panel, do the following:
   1. From the **Category** dropdown, select at least one category that applies to the integration (required).
   2. Under **API key**, paste the API key you generated in PagerDuty (required).
   3. Optionally, toggle on **Read-only API key** if you created the key with read-only permissions.
4. Click **Test connection**. A successful connection means your integration is configured correctly.
5. Click **Save**.

{% hint style="info" %}
To modify an existing configuration, see [Modifying an integration configuration](https://docs.cortex.io/ingesting-data-into-cortex/integrations#modifying-an-integration-configuration).
{% endhint %}


# Connecting entities to PagerDuty

Connect entities to PagerDuty automatically or manually via the entity's descriptor YAML

{% hint style="info" %}
Cortex connects to many third-party vendors whose system interfaces frequently change. As a result, integration behavior or configuration steps may shift without notice. If you encounter unexpected issues, check with your system administrator or refer to the vendor's documentation for the most current information. Additionally, integration sync times vary and are subject to scheduling overrides and timing variance.
{% endhint %}

This article explains how to connect entities to PagerDuty. For configuration instructions, see [Configuring the integration for PagerDuty](/ingesting-data-into-cortex/integrations/pagerduty#configuring-pagerduty). For instructions on using the integration, see [Using the integration for PagerDuty](/ingesting-data-into-cortex/integrations/pagerduty/using-the-integration-for-pagerduty).

{% hint style="info" %}
Cortex runs the following background jobs for PagerDuty:&#x20;

* On-call information on the Engineering homepage is refreshed every 60 minutes.
* Services used for automapping and active incidents are fetched approximately every 5 minutes, or however long the refresh takes.
* User data for identity mapping is synced daily at 10 a.m. UTC.&#x20;
  {% endhint %}

## Connecting an entity to PagerDuty

Cortex entities are connected to PagerDuty in one of two ways: automatically through discovery, or explicitly by defining a PagerDuty service, schedule, or escalation policy in the entity's descriptor YAML.

### Discovering entities automatically

By default, Cortex uses the [Cortex tag](/ingesting-data-into-cortex/entities-overview/entities#cortex-tag) (e.g. `checkout-api`) or the entity's name as the "best guess" for PagerDuty services. For example, if the Cortex tag is `checkout-api`, the corresponding service in PagerDuty should also be `checkout-api`.&#x20;

If your PagerDuty services don't cleanly match the Cortex tag or name, define the connection in the [entity descriptor](#connecting-via-an-entity-descriptor) instead.

#### Considerations for registering PagerDuty entities

Cortex recommends setting up PagerDuty at the **service level** by registering service entities with PagerDuty services, rather than configuring team entities with a PagerDuty schedule.

If PagerDuty is set up on a service level, you can see current on-call information listed within a given service's page. If PagerDuty is set up on the team level, you can only view on-call rotation information from a team page.

Other benefits of setting up PagerDuty on a service level include:

* Structuring PagerDuty 1-1 with services enables better alert routing and analytics, something organizations struggle with more when PagerDuty is set up on a team level.
* With a service-level setup, it's easier to enforce a compliant on-call policy for all services in PagerDuty, especially when making use of Scorecards.
* The service-level setup is less reliant on team members tagging incidents with service information because services and incidents are already linked.
* You gain the ability to get data from your Cortex catalog into PagerDuty, such as tier and criticality. By tying the service entities in the catalog to those in PagerDuty, you can automate processes and streamline severity protocols.

#### Viewing on-call data only

If you only want to view on-call data for entities, and do not want incidents displayed in Cortex, you can register the escalation policy ID for an entity. See [Defining an escalation policy](#defining-an-escalation-policy) below.

### Connecting via entity descriptor

To explicitly connect an entity to PagerDuty, add the `x-cortex-oncall` block to the entity's YAML, specifying a PagerDuty service, schedule, or escalation policy.&#x20;

<table><thead><tr><th width="82.71484375">Field</th><th width="387.38671875">Description</th><th align="center">Required?</th></tr></thead><tbody><tr><td><code>id</code></td><td>PagerDuty ID for the service, schedule, or escalation policy</td><td align="center"><i class="fa-check">:check:</i></td></tr><tr><td><code>type</code></td><td>SERVICE, SCHEDULE, or ESCALATION_POLICY</td><td align="center"><i class="fa-check">:check:</i></td></tr></tbody></table>

{% hint style="warning" %}
You can only set up one of the three options below per entity.
{% endhint %}

#### Defining a PagerDuty service

In PagerDuty, find the [service ID value](https://support.pagerduty.com/main/docs/service-directory#configure-service-standards-settings). The URL for the service contains the ID, e.g. `PDEF456` in `https://yourdomain.pagerduty.com/services/PDEF456`.&#x20;

You can only configure one service ID per entity.

```yaml
x-cortex-oncall:
  pagerduty:
    id: PDEF456
    type: SERVICE
```

#### Defining a schedule

In PagerDuty, find the [schedule ID](https://developer.pagerduty.com/api-reference/3f03afb2c84a4-get-a-schedule). The URL for the schedule contains the ID, e.g. `PABC123` in `https://yourdomain.pagerduty.com/schedules/PABC123`.&#x20;

You can only configure one schedule per entity.

```yaml
x-cortex-oncall:
  pagerduty:
    id: PABC123
    type: SCHEDULE
```

#### Defining an escalation policy

In PagerDuty, find the [escalation policy ID](https://developer.pagerduty.com/api-reference/51b21014a4f5a-list-escalation-policies). The URL for the escalation policy contains the ID, e.g. `P7LVMYP` in `https://yourdomain.pagerduty.com/escalation_policies/P7LVMYP`. You can only configure one escalation policy per entity.

Linking a Cortex entity to a PagerDuty escalation policy surfaces only on-call information in Cortex, not incidents. This is useful for teams that want to show on-call schedules without incident visibility.

```yaml
x-cortex-oncall:
  pagerduty:
    id: P7LVMYP
    type: ESCALATION_POLICY
```

### Identity mappings

Cortex maps email addresses in your PagerDuty instance to email addresses that belong to team members in Cortex. When [identity mapping](/configure/settings/managing-users/identity-mapping) is set up, users can see their personal on-call status from the [Engineering homepage](/streamline/homepage).

## Enabling the On-call Assistant

{% hint style="info" %}
The On-call Assistant only works for service-level PagerDuty registrations, since these notifications are related to affected services.
{% endhint %}

After configuring the integration, you can turn on the On-call Assistant, which notifies users via Slack when an incident is triggered in PagerDuty. Notifications include runbooks, links, dependencies, and key information about the affected entity. For instructions, see [On-call Assistant](/ingesting-data-into-cortex/entities-overview/entities/oncall-assistant).<br>


# Using the integration for PagerDuty

How to use the integration for PagerDuty in Cortex

This article explains how to use the integration for PagerDuty. For configuration instructions, see [Configuring the integration for PagerDuty](/ingesting-data-into-cortex/integrations/pagerduty#configuring-pagerduty). For instructions on connecting PagerDuty to entities, see [Connecting entities to PagerDuty](/ingesting-data-into-cortex/integrations/pagerduty/connecting-entities-to-pagerduty).

After you configure the PagerDuty integration, Cortex surfaces on-call and incident data across the app on:

### Entity pages

View current on-call information in the **On-call** block on an entity's metadata sidebar, and on the entity's details page under **Connections > On-call**.

<div align="left" data-with-frame="true"><figure><img src="/files/qwoXpE8TU9MMNXMysyo0" alt="On-call information on an entity&#x27;s details page." width="375"><figcaption></figcaption></figure></div>

Select the **Events** tab in an entity's left side panel to view recent events pulled in from PagerDuty.

<div align="left" data-with-frame="true"><figure><img src="/files/YkWk1zpem8gOq1ezpSoA" alt="The Events page." width="375"><figcaption></figcaption></figure></div>

{% hint style="info" %}
Escalation policy and service details are hyperlinked to the corresponding pages in your PagerDuty instance.
{% endhint %}

### Engineering homepage

The PagerDuty integration allows Cortex to pull on-call information into the **My on-calls** block on the Engineering homepage. On-call data from PagerDuty is refreshed every 60 minutes.

<div align="left" data-with-frame="true"><figure><img src="/files/swedkegCzhkwkZMAplTr" alt="The &#x27;My on-calls&#x27; section of the Engineering homepage." width="375"><figcaption></figcaption></figure></div>

### Eng Intelligence

Cortex also pulls in metrics from PagerDuty for Eng Intelligence, which displays MTTR, incidents opened, and incidents opened per week.

## Other ways to use the integration for PagerDuty

### Retrieving on-call information in Slack

If you have the Slack integration set up, you can ask the AI Assistant for current on-call information. Mention `@Cortex` in a channel or direct message and ask a question like "Who's on call for payments-api?" This works for both services and teams with registered PagerDuty schedules or escalation policies.

For setup and usage details, refer to [Using the AI assistant](/ingesting-data-into-cortex/integrations/slack/using-the-integration-for-slack-ai-assistant#using-the-ai-assistant).

### Scorecards and CQL

With the PagerDuty integration, you can create Scorecard rules and write CQL queries based on incidents, escalations, and on-call metadata.

See more examples in the [CQL Explorer](https://app.getcortexapp.com/admin/cql-explorer) in Cortex.

<details>

<summary>Check if on-call is set</summary>

Check if entity has a registered service, schedule, or escalation policy. If the service does not have any registrations in its entity descriptor, Cortex searches for PagerDuty services matching the tag defined in the entity's `x-cortex-tag` field.

**Definition** - `oncall (==/!=) null`

**Example**

For a Scorecard focused an production readiness, you can use this expression to make sure on-call is defined for entities:

```
oncall != null
```

This rule passes if an entity has a service, schedule, or escalation policy set.

</details>

<details>

<summary>Forbidden contact methods</summary>

Number of users in each entity's escalation policy with missing or forbidden contact methods.

Allowed contact methods:

* "SMS"
* "PHONE"
* "EMAIL"
* "PUSH\_NOTIFICATION"
* "SLACK"

**Definition** - `oncall.usersWithoutContactMethods(allowed=<allowed>, onlyCurrentOncall=<boolean>).length`

**Example**

For a Scorecard focused on ownership, you can use this expression to make sure users have required contact methods enabled:

```
oncall.usersWithoutContactMethods(allowed=["SMS", "PHONE"]).length == 0
```

This rule passes if every user in an associated escalation policy has either SMS or phone calls enabled as their contact method.

You can also use this expression in the query builder to find users that lack the required contact method:

```
oncall.usersWithoutContactMethods(allowed=["EMAIL"]) > 0
```

This query surfaces users without email addresses.

If you want to check only current on-call users, you can use the `onlyCurrentOncall` parameter:

```
oncall.usersWithoutContactMethods(allowed=["EMAIL"], onlyCurrentOncall=true) > 0
```

When this parameter is set to `false` or omitted, the expression checks all users in the associated escalation policy for the next 3 months.

</details>

<details>

<summary>Incident response analysis</summary>

Get detailed [on-call analysis stats](https://developer.pagerduty.com/api-reference/694e92fe4f943-get-aggregated-service-data) for each entity:

* Mean assignment count
* Mean engaged seconds
* Mean engaged user count
* Mean seconds to engage
* Mean seconds to first ack
* Mean seconds to mobilize
* Mean seconds to resolve
* Total business-hour erruptions
* Total engaged seconds
* Total escalation count
* Total off-hour erruptions
* Total sleep-hour erruptions
* Total snoozed seconds
* Total incident count
* Up time percent

PagerDuty updates its analytics data once per day, and it can take up to 24 hours before new incidents appear in the analytics API.

**Note that this only works if the entity has a registered PagerDuty service ID or if the PagerDuty service name matches the entity tag.**

**Definition** - `oncall.analysis(lookback = <duration>, priority = <List<String>>)`

**Examples**

PagerDuty analytics can easily be used to craft rules for a DORA metrics Scorecard.

For **mean time to acknowledge**, you can use the `meanSecondsToFirstAck` schema definition:

```
oncall.analysis(lookback = duration("P7D"), priority = ["P1", "P2"]).meanSecondsToFirstAck <= 300
```

Entities pass this rule if incidents in the last week were acknowledged within 5 minutes.

For **mean time to resolve**, you can use `meanSecondsToResolve` to make sure that incidents were handled within an hour:

```
oncall.analysis(lookback = duration("P7D"), priority = ["P1"]).meanSecondsToResolve < 3600
```

You can also use this expression to write a rule that checks an entity's change failure rate:

```
oncall.analysis(lookback = duration("P7D")).totalIncidentCount == 0
```

This rule passes if there weren't any incidents in the last week.

</details>

<details>

<summary>Incidents</summary>

Get incident data for each entity:

* Assignee ID
* Created at
* Incident ID
* Last updated
* Resolved at
* Service ID
* Status

**Note that this only works if the entity has a registered PagerDuty service ID or if the PagerDuty service name matches the entity tag.**

**Definition** - `oncall.incidents(lookback = <duration>)`

**Examples**

For a Scorecard focused on service maturity or quality, you can use this expression to check the number of incidents opened in the last month:

```
oncall.incidents(lookback = duration("P1M")).length < 15
```

Entities pass this rule if they have fewer than 15 incidents opened in the last month.

You can also use this expression to make sure there aren't incidents that remained open over the last month:

```
oncall.incidents(lookback=duration("P1M")).filter((incident) => incident.status.matches("TRIGGERED|ACKNOWLEDGED")).length < 1
```

Or you can check for incidents that took a certain amount of time to resolve:

```
oncall.incidents(lookback=duration("P1M")).filter((incident) => incident.createdAt.until(incident.resolvedAt) > duration("P-2D")).length < 2
```

Entities pass this rule if there were 0 or 1 incidents in the last month that took more than 2 days to resolve.

</details>

<details>

<summary>Number of escalations</summary>

Number of escalation tiers in escalation policy.

**Definition** - `oncall.numOfEscalations()`

**Example**

This expression could be used in a Scorecard focused on production readiness or service maturity:

```
oncall.numOfEscalations() >= 2
```

This rule checks that there are at least two tiers in an escalation policy for a given entity, so that if the first on-call does not ack, there is a backup.

While making sure an on-call policy set is a rule that would be defined in a Scorecard's first level, a rule focused on escalation tiers would make more sense in a higher level.

</details>

<details>

<summary>On-call metadata</summary>

On-call metadata, including type, id, and name.

**Definition** - `oncall.details()`

**Examples**

To find all entities with a schedule-type on-call registration, you can use this expression in the Query builder:

```
oncall.details().type == "schedule"
```

If you're migrating on-call policies, you could use this rule to check for outdated policies. For example, assume that all outdated PagerDuty policies start with "Legacy" in their titles.

```
oncall.details().id.matches("Legacy*") == false
```

Entities with on-call policies that start with "Legacy" fail, while those with other policy names pass.

</details>

## Triggering an incident

A given entity can have a PagerDuty service, schedule, or escalation policy defined, as described in [Connecting via an entity descriptor](/ingesting-data-into-cortex/integrations/pagerduty/connecting-entities-to-pagerduty#connecting-via-an-entity-descriptor). Only entities with a PagerDuty service defined include the option to trigger an incident directly from Cortex.

Your PagerDuty API key must include the `Write` permission to trigger incidents from an entity.

**To trigger an incident in PagerDuty**:

1. In Cortex, navigate to an entity.&#x20;
2. From the entity's left sidebar, select **Incidents**.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/JGgt81c73aTvQImYozZJ" alt="The &#x27;Incidents&#x27; tab on the entity&#x27;s left sidebar." width="375"><figcaption></figcaption></figure></div>
3. In the upper-right corner of the **Incidents** page, click **Trigger incident**. The **Trigger incident** side panel opens.
4. Do the following:
   1. Under **Title**, enter a name for the incident (required).&#x20;
   2. Under **Description**, enter a description of the incident.
   3. From the **Urgency** dropdown, select a severity level.
5. Click **Trigger incident**.&#x20;
6. Click **Click here** to view the incident in PagerDuty.
7. Click **Close** to collapse the **Trigger incident** side panel.

## Viewing PagerDuty integration logs

{% hint style="info" %}
This feature is available in Cortex cloud.
{% endhint %}

While viewing an integration's settings page, select the **Logs** tab to view error logs from the last 7 days. You can filter the logs list by configuration and by operation (for example, you could filter to view errors surfaced only via Scorecards).

<div align="left" data-with-frame="true"><figure><img src="/files/x8JmoPqXZTJ7YHeFJpOA" alt="The &#x27;Logs&#x27; tab on an integration&#x27;s settings page shows error information over the past 7 days."><figcaption></figcaption></figure></div>

Click into a row to get more information, including time stamp, status code, full error, and request path.


# Prometheus

{% hint style="info" %}
Cortex connects to many third-party vendors whose system interfaces frequently change. As a result, integration behavior or configuration steps may shift without notice. If you encounter unexpected issues, check with your system administrator or refer to the vendor's documentation for the most current information. Additionally, integration sync times vary and are subject to scheduling overrides and timing variance.
{% endhint %}

## Overview

[Prometheus](https://prometheus.io/) is an open-source monitoring and analytics platform that allows customers to analyze, visualize, automate, and alert on metrics data.

Integrating Cortex with Prometheus allows you to:

* [View SLO information](#view-prometheus-data-in-entity-pages) from Prometheus on entity pages in Cortex
* Create [Scorecards](#scorecards-and-cql) that track progress and drive alignment on projects involving Prometheus SLOs

## How to configure Prometheus with Cortex

There are two options for integrating Prometheus: the default configuration method and Cortex Axon Relay, a relay broker allows you to securely connect your on-premises Prometheus data.

### Prerequisite

Before getting started, set up [basic authentication](https://prometheus.io/docs/guides/basic-auth/) credentials in Prometheus.

{% tabs %}
{% tab title="Default configuration" %}
**Configure the integration in Cortex**

1. In Cortex, navigate to the [Prometheus settings page](https://app.getcortexapp.com/admin/integrations/prometheus):
   * Click **Integrations** from the main nav. Search for and select **Prometheus**.
2. Click **Add integration**.
3. Configure the Prometheus integration form:
   * **Account alias**: Enter your account alias.
   * **Username** and **Password**: Enter your Prometheus basic auth credentials.
   * **Host**: Enter your self-managed Prometheus hostname.
   * **Tenant ID**: Optionally, enter your tenant ID.
     * If you have multiple tenants, you can enter an ID here to monitor a specific tenant.
4. Click **Save**.
   {% endtab %}

{% tab title="Relay broker" %}
**Configure Prometheus with Cortex Axon Relay**

See [Internally hosted integrations](/ingesting-data-into-cortex/integrations/axon-relay) for instructions. Make sure to follow the Prometheus-specific instructions for the docker-compose.yml file.
{% endtab %}
{% endtabs %}

**Configure the integration for multiple Prometheus accounts**[**​**](https://docs.cortex.io/docs/reference/integrations/prometheus#configure-the-integration-for-multiple-propsintegration-accounts)

The Prometheus integration has multi-account support. You can add a configuration for each additional by repeating the process above.

Each configuration requires an alias, which Cortex uses to correlate the designated with registrations for various entities. Registrations can also use a default configuration without a listed alias. You can edit aliases and default configurations from the Prometheus page in your Cortex settings. Select the edit icon next to a given configuration and toggle **Set as default** on. If you only have one configuration, it will automatically be set as the default.

## Connecting Cortex entities to Prometheus

### Linking SLOs in Cortex

You can create and manage SLOs by listing relevant SLIs through queries.

```yaml
x-cortex-slos:
  prometheus:
    - errorQuery: sum(rate(http_server_requests_seconds_count{code=~"(5..|429)"}[5m]))
      totalQuery: sum(rate(http_server_requests_seconds_count[5m]))
      slo: 99.95
      alias: my-prometheus-instance # alias is optional and only relevant if you have opted into multi account support
      name: my-slo-name
```

| Field      | Description                                                                                                                                                                                                         |
| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| errorQuery | Query that indicates error events for your metric.                                                                                                                                                                  |
| totalQuery | Query that indicates all events to be considered for your metric.                                                                                                                                                   |
| slo        | Target number for SLO.                                                                                                                                                                                              |
| alias      | Ties the SLO registration to a Prometheus instance listed under Settings → Prometheus. The alias parameter is optional, but if not provided the SLO will use the default configuration under Settings → Prometheus. |
| name       | The SLO's name in Prometheus. The name parameter is optional.                                                                                                                                                       |

### How Cortex calculates Prometheus SLOs

When Cortex gets an SLO from Prometheus, the following query is calculated for it:

```
(1 - ({errorQuery}) / ({totalQuery}))
```

This value is calculated and resolved on an hour window, and calculated back for 7 days. Cortex averages the value for each 1-hour window, then averages each of those hourly averages across the lookback period, before displaying it in your Cortex workspace.

The value is updated when the entity page is loaded and when Scorecards are evaluated.

## Using the Prometheus integration

### View Prometheus data in entity pages

When an SLO is defined in an entity's descriptor, you'll see detailed data about SLOs in the **Monitoring** page in the sidebar of an [entity details page](/ingesting-data-into-cortex/entities-overview/entities/details). See the SLO query, target, the current value for each SLO, and the period of time the SLO is being calculated for. For example, if the time listed is "7 days ago," then the SLO is looking at the time range starting 7 days ago to now\..

### Scorecards and CQL

With the Prometheus integration, you can create Scorecard rules and write CQL queries based on Prometheus SLOs.

See more examples in the [CQL Explorer](https://app.getcortexapp.com/admin/cql-explorer) in Cortex.

<details>

<summary>SLOs</summary>

SLOs associated with the entity via ID or tags. You can use this data to check whether an entity has SLOs associated with it, and if those SLOs are passing.

**Definition:** `slos: List<SLO>`

**Examples**

In a Scorecard, you can use this expression to make sure an entity is passing its SLOs:

```
slos().all((slo) => slo.passing) == true
```

Use this expression to make sure latency Service Level Indicator (SLI) value is above 99.99%:

```
slos().filter((slo) => slo.name.matchesIn("latency") and slo.sliValue >= 0.9999).length > 0
```

</details>

### View integration logs <a href="#still-need-help" id="still-need-help"></a>

{% hint style="info" %}
This feature is available in Cortex cloud.
{% endhint %}

While viewing an integration's settings page, select the **Logs** tab to view error logs from the last 7 days. You can filter the logs list by configuration and by operation (for example, you could filter to view errors surfaced only via Scorecards).

<div align="left" data-with-frame="true"><figure><img src="/files/x8JmoPqXZTJ7YHeFJpOA" alt="The &#x27;Logs&#x27; tab on an integration&#x27;s settings page shows error information over the past 7 days."><figcaption></figcaption></figure></div>

Click into a row to get more information, including time stamp, status code, full error, and request path.

## Still need help?[​](https://docs.cortex.io/docs/reference/integrations/aws#still-need-help) <a href="#still-need-help" id="still-need-help"></a>

The following options are available to get assistance from the Cortex Customer Engineering team:

* **Email**: <help@cortex.io>, or open a support ticket in the in app Resource Center
* **Slack**: Users with a connected Slack channel will have a workflow added to their account. From here, you can either @CortexTechnicalSupport or add a `:ticket:` reaction to a question in Slack, and the team will respond directly.

Don’t have a Slack channel? Talk with your Customer Success Manager.




---

[Next Page](/llms-full.txt/1)

