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

# Getting Data Into the Catalog

> Compare the ways to populate a Rootly catalog — manual entry, the bulk API, and Catalog Sync — and choose the one that matches where your data already lives.

A catalog is only as useful as the data in it, and there are four ways to put data there. They are not ranked — the right one depends on where the truth already lives and how often it changes.

***

## The Four Routes

| Route | Best when | Keeps itself current |
| - | - | - |
| **Native integration sync** | Your data is in Backstage, ServiceNow, or Cortex | Yes |
| [Catalog Sync](/catalog-sync) | The truth lives in another system of record with no native integration | Yes |
| [Bulk API](/api-reference/overview) | You already have the data in a system you can script against | Only if you script it |
| [Manual entry](/managing-custom-catalogs) | The list is short, stable, and has no upstream source | No |

The question that decides it is not "how much data" — it is **where the truth lives**. If your service list is authoritative somewhere else, anything that copies it once will be wrong within a month. If Rootly *is* the source of truth for a catalog, a sync tool is machinery you do not need.

***

## Native Integration Sync

If your data already lives in **Backstage**, **ServiceNow**, or **Cortex**, check the integration before reaching for anything else — each can populate catalogs directly, with no CLI to run and no pipeline to operate.

| Integration | What it brings in |
| - | - |
| [Backstage](/integrations/backstage/installation) | Backstage catalog entities |
| [ServiceNow](/integrations/service-now) | CMDB configuration items |
| [Cortex](/integrations/cortex/overview) | Cortex catalog entries |

Records populated this way are **protected while the sync is active** — the integration is the owner. Rootly will not delete a synced entity or change a synced catalog's properties, and the web app will not edit a synced entity's name or description. For Backstage, this protection is available to some organizations. It is worth knowing before someone tries to correct a value by hand and cannot.

***

## Manual Entry

Add entities through the Rootly UI. See [Managing Custom Catalogs](/managing-custom-catalogs).

Use it for catalogs that are genuinely small and genuinely stable — a list of compliance regimes, a handful of business units, the four regions you operate in.

The failure mode is predictable: a manually maintained catalog is accurate on the day it is created and decays from there, because nothing tells you when it has gone stale. If you find yourself updating one regularly, that is the signal to move it to one of the routes below.

***

## Bulk API

Two endpoints handle bulk changes:

| Endpoint | Purpose |
| - | - |
| `POST /v1/catalogs/{catalog_id}/entities/bulk_upsert` | Create or update entities in one call |
| `POST /v1/catalogs/{catalog_id}/entities/bulk_delete` | Remove entities in one call |

Single-entity and property endpoints exist too. The **API Reference** tab carries the full set with their schemas — it is generated from the spec, so it stays right when a list like this one would not.

**Upsert, not insert.** `bulk_upsert` matches entities on `external_id`, which every record in the call must carry: a record whose `external_id` already exists updates that entity, and only a new one creates an entity. That is what makes it safe to run repeatedly. Each call takes up to 100 records. A nightly job that upserts your whole service list converges on the right state instead of accumulating copies.

Reach for this when the data lives somewhere Catalog Sync does not read, or when you want the sync logic inside a pipeline you already operate.

***

## Catalog Sync

[`rootly-catalog-sync`](/catalog-sync) is a CLI that reconciles an external source of truth into a catalog, one way. Point it at a directory of YAML in a GitHub repo, a CSV, a GraphQL endpoint, or any command that prints JSON, and run it on a schedule. Rootly mirrors the source.

The full list of source types is on the [Catalog Sync](/catalog-sync#sources) page.

This is the route to prefer whenever a source of truth exists. It is one-way by design: the external system stays authoritative and Rootly follows, so there is no question about which side wins when they disagree.

<Tip>
  `exec` and `http` between them cover most systems that have no dedicated source type. If your data is reachable by a command or a REST call, you probably do not need to write a custom integration.
</Tip>

***

## Choosing

Four questions, in order:

<Steps>
  <Step title="Is your data in Backstage, ServiceNow, or Cortex?">
    Use that integration's own catalog sync. It is the least machinery for the same result.
  </Step>

  <Step title="Does the truth live outside Rootly, somewhere else?">
    Use **Catalog Sync**. Check the [source list](/catalog-sync#sources) first — if one matches, the work is configuration rather than code.
  </Step>

  <Step title="If it does, but Catalog Sync can't reach it?">
    Use the **bulk API** on a schedule. `bulk_upsert` is safe to re-run, so the job can be simple.
  </Step>

  <Step title="Is Rootly the source of truth for this catalog?">
    Then **manual entry** is correct, and adding sync machinery would create a second place for the data to disagree with itself.
  </Step>
</Steps>

***

## Related Pages

<CardGroup cols={2}>
  <Card title="Managing Custom Catalogs" icon="table-list" href="/managing-custom-catalogs">
    Creating a catalog and adding entities by hand.
  </Card>

  <Card title="Catalog Sync" icon="arrows-rotate" href="/catalog-sync">
    The CLI, its nine sources, and how to run it in CI.
  </Card>
</CardGroup>


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