EvoHub DocsEvoHub Docs Sign in

Catalog API

Use with AI
View as MarkdownThis page as plain text, for pasting into an AI tool Open in ClaudeAsk Claude questions about this page Open in ChatGPTAsk ChatGPT questions about this page
Connect to Cursor / VS Code / ClaudeSearch and read these docs from your AI tool (MCP server)

MCP server URL

https://docs.evohub.io/mcp

Claude Code

claude mcp add --transport http evohub-docs https://docs.evohub.io/mcp

Claude (claude.ai and Claude Desktop): Settings → Connectors → Add custom connector, and paste the URL above.

Claude Desktop — claude_desktop_config.json

{
  "mcpServers": {
    "evohub-docs": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "https://docs.evohub.io/mcp"
      ]
    }
  }
}

Cursor — ~/.cursor/mcp.json

{
  "mcpServers": {
    "evohub-docs": {
      "url": "https://docs.evohub.io/mcp"
    }
  }
}

VS Code — .vscode/mcp.json

{
  "servers": {
    "evohub-docs": {
      "type": "http",
      "url": "https://docs.evohub.io/mcp"
    }
  }
}

The Catalog API lets scripts and CI jobs do what the Catalog console does: declare services and keep them current, read the inventory, decide which service a resource belongs to, read drift and SLA reports, and export everything for an audit. Every endpoint, with its parameters, schemas and errors, is in the Catalog API reference. This page shows the common tasks and the rules that apply to all of them.

Paths below are relative to https://evohub.io, and every one starts with /api/v1/catalog/. Requests need an API key, sent as described in API overview.

Scopes

To Scope
Read services, tiers and SLA reports catalog:component:read
Declare, change and delete services, set their RACI, manage tiers catalog:component:write
Read resources, changes, applications, images and the map catalog:resource:read
Accept and reject matches, put a resource or an application in a service catalog:resource:write
Read environments and sources catalog:source:read
Manage environments, rename, pause and resume sources catalog:source:write
Read cloud accounts identity:cloudaccount:read
Connect and manage cloud accounts identity:cloudaccount:write (connecting also needs catalog:source:write)

The match queue, drift, a service's resources and the inventory export need both catalog:component:read and catalog:resource:read. A key without a scope gets 403, never 401. See Catalog permissions.

Declare a service

curl https://evohub.io/api/v1/catalog/components \
  -H "Authorization: Bearer $EVOHUB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "slug": "payments-api",
    "display_name": "Payments API",
    "owner_team_id": "team_3b6f0e2a-1c4d-4e8f-9a7b-2d5c6e8f0a1b",
    "tier": 1,
    "runbook_url": "https://wiki.acme.example/runbooks/payments"
  }'

slug and display_name are required; the slug can never change. Every endpoint that takes a service accepts its ID (cmp_…) or its slug, so GET /api/v1/catalog/components/payments-api works. PATCH changes only the fields you send; send null to clear owner_team_id, tier or sla_overrides, and "" to clear a text field.

A pipeline can keep services in step with a repository: PATCH each one, and POST it when the answer is 404.

Find what nobody owns

curl "https://evohub.io/api/v1/catalog/resources?unowned=true&exclude_kind=Namespace,Node" \
  -H "Authorization: Bearer $EVOHUB_API_KEY"

Lists page with cursor: pass the previous answer's pagination.next_cursor until has_more is false. The first page of the resource and application lists also carries pagination.total. Other useful filters: image=nginx (any tag of a repository), floating=true (images with no fixed version), component_id, environment_id and status.

GET /api/v1/catalog/drift returns the whole drift report in one answer.

Decide the match queue

# What is waiting
curl https://evohub.io/api/v1/catalog/matches \
  -H "Authorization: Bearer $EVOHUB_API_KEY"

# Accept one
curl -X POST https://evohub.io/api/v1/catalog/matches/$MATCH_ID/accept \
  -H "Authorization: Bearer $EVOHUB_API_KEY"

# Or put an application in a service directly
curl -X POST https://evohub.io/api/v1/catalog/applications/$APP_ID/component \
  -H "Authorization: Bearer $EVOHUB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"component": "payments-api"}'

A rejected proposal is never proposed again. {"component": null} unbinds. See Matching and drift.

Read an SLA report

curl "https://evohub.io/api/v1/catalog/components/payments-api/sla-report?month=2026-10" \
  -H "Authorization: Bearer $EVOHUB_API_KEY"

Without month, the current month so far. Each part's status is measured, not_connected or unavailable.

Export the inventory

GET /api/v1/catalog/exports/inventory returns every asset not gone, with its application, service, owner team, tier, availability target and RACI: at most 50,000 rows, with truncated when there were more. Teams and people are their IDs.

Cloud accounts

Connections are created first and given access second: POST /api/v1/catalog/connections returns the connection with its external_id; then, for AWS, download the role template from GET /api/v1/catalog/connections/{id}/template, create the role, and PATCH its role_arn. POST /api/v1/catalog/connections/{id}/check tries the access and answers {"ok": true, "account_id": "…"} or {"ok": false, "error": "…"}. See Cloud accounts.

Things to know

  • Agents only. The routes under /api/v1/catalog/ingest/ are for the EvoHub agent, which signs each request with its own key. An API key cannot send inventory, and an agent cannot read.
  • Observations are read-only. Resources and applications are never created or edited through the API; only which service they belong to is decided here. Sources have no create or delete either: an agent's appears when it first reports, and is retired by revoking the agent.
  • Parts you cannot read are left out. A service's detail omits observations for a key without catalog:resource:read; a resource's or application's omits proposals without catalog:component:read; a cloud account's external_id is empty without identity:cloudaccount:write.
  • Strict bodies. A field an endpoint does not know is refused with INVALID_BODY, so a typo never reads as success.
  • Errors. Branch on error.code, for example NOT_FOUND, SLUG_TAKEN, SLUG_IMMUTABLE, MATCH_DECIDED or ENVIRONMENT_IN_USE. The general rules are in Errors.
Last updated Powered by