Skip to main content

Check out Port for yourself ➜ 

Sync Port Services to incident.io

This guide demonstrates how to sync service entities from Port into incident.io's catalog, ensuring better visibility and context for your services during incident management.

You can use either of these methods:

  • catalog-importer (recommended): incident.io's official CLI tool, designed to run as part of CI/CD or on a cronjob. It syncs structured data from Port (and other sources) into the incident.io catalog.
  • Custom GitHub workflow: A GitHub Actions workflow that fetches entities from Port and pushes them to incident.io via their API.

Prerequisites

  • Complete the onboarding process.
  • An incident.io account with admin access to create API keys.
  • A Service blueprint in Port to represent the service entities you want to sync to incident.io. You should already have one installed during the onboarding process.
  • For the custom GitHub workflow: A GitHub repository and Port's GitHub app installed.
Admin access required

You need admin access to your incident.io organization to create API keys. If you don't have admin access, contact your incident.io administrator to create the API key for you.

Setup

The catalog-importer is incident.io's official tool for syncing catalog data. It is designed to run as part of CI/CD or on a cronjob and supports multiple data sources, including Port.

Install catalog-importer

macOS (Homebrew):

brew tap incident-io/homebrew-taps
brew install catalog-importer

Other platforms:

Install from the releases page or run:

go install -v github.com/incident-io/catalog-importer/v2/cmd/catalog-importer@latest

Set up API keys

Create an incident.io API key with permissions to view and manage catalog types and entries. Set:

export INCIDENT_API_KEY="your-incident-io-api-key"

For Port, use your Port credentials:

export PORT_CLIENT_ID="your-port-client-id"
export PORT_CLIENT_SECRET="your-port-client-secret"
Selecting a Port API URL by account region

The port_region, port.baseUrl, portBaseUrl, port_base_url and OCEAN__PORT__BASE_URL parameters select which Port API instance to use:

Create the fetch script

Create fetch-from-port.sh to fetch entities from Port and output JSON for the catalog-importer:

#!/bin/bash
set -e

PORT_BASE_URL="${PORT_BASE_URL:-https://api.getport.io}"
BLUEPRINT_ID="${BLUEPRINT_ID:-service}"

TOKEN=$(curl -s -X POST "${PORT_BASE_URL}/v1/auth/access_token" \
-H "Content-Type: application/json" \
-d "{\"clientId\": \"$PORT_CLIENT_ID\", \"clientSecret\": \"$PORT_CLIENT_SECRET\"}" \
| jq -r '.accessToken')

curl -s -X GET "${PORT_BASE_URL}/v1/blueprints/${BLUEPRINT_ID}/entities" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
| jq '[.entities[] | {
external_id: .identifier,
name: .title,
url: .properties.url // "",
readme: .properties.readme // "",
language: .properties.language // "",
lifecycle: .properties.lifecycle // "",
type: .properties.type // ""
}]'

Create the importer config

Create importer.jsonnet. The catalog-importer creates the catalog type automatically on first sync.

Blueprint schema matching

Ensure the attribute IDs in the config (url, readme, etc.) match the property names in your Port Service blueprint.

{
sync_id: 'port-services',

pipelines: [
{
sources: [
{
exec: {
command: ['bash', 'fetch-from-port.sh'],
},
},
],
outputs: [
{
name: 'Port Services',
description: 'Services entities synced from Port',
type_name: 'Custom["PortServices"]',
categories: ['service'],
source: {
external_id: '$.external_id',
name: '$.name',
},
attributes: [
{ id: 'url', name: 'URL', type: 'String', source: '$.url' },
{ id: 'readme', name: 'Readme', type: 'Text', source: '$.readme' },
{ id: 'language', name: 'Language', type: 'String', source: '$.language' },
{ id: 'lifecycle', name: 'Lifecycle', type: 'String', source: '$.lifecycle' },
{ id: 'type', name: 'Type', type: 'String', source: '$.type' },
],
},
],
},
],
}

For full configuration options, see the catalog-importer config reference.

Validate and sync

catalog-importer validate --config=importer.jsonnet
catalog-importer sync --config=importer.jsonnet --dry-run
catalog-importer sync --config=importer.jsonnet

Run in CI/CD

You can run the catalog-importer in GitHub Actions using the Docker image:

name: Sync Port to incident.io

on:
schedule:
- cron: "0 */2 * * *"
workflow_dispatch:

jobs:
sync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Sync catalog
run: |
docker run --rm \
-v ${{ github.workspace }}/incident-io:/config \
-w /config \
-e INCIDENT_API_KEY=${{ secrets.INCIDENT_API_KEY }} \
-e PORT_CLIENT_ID=${{ secrets.PORT_CLIENT_ID }} \
-e PORT_CLIENT_SECRET=${{ secrets.PORT_CLIENT_SECRET }} \
incidentio/catalog-importer:latest \
sync --config importer.jsonnet

Store your config and fetch-from-port.sh in an incident-io directory in your repo. For Port's EU region, add -e PORT_BASE_URL=https://api.eu.getport.io to the docker run command.

For more details, see the catalog-importer documentation.

Limitations

Note that incident.io can currently ingest up to 50,000 catalog items. Keep this limit in mind when scaling your service catalog.