Configuration
In this page we will cover the configuration steps that apply to both installation methods (hosted by Port and self-hosted). We will walk through the prerequisites you need to gather, how to configure resource mapping, and advanced configuration options for complex scenarios.
How it works
The Ocean custom integration uses a two-step setup:
- Installation - Configure connection settings that apply to all API calls (hosted by Port or self-hosted).
- Resource mapping - Define which endpoints to sync and how to map them to Port entities.
Resource mapping
After installation, you define which endpoints to sync in your port-app-config.yml file (or using the integration's configuration in Port).
This is where you map each API endpoint to Port entities - similar to how you've mapped GitHub repositories or Jira issues in other integrations.
Endpoint-as-kind feature
The kind field is now the endpoint path itself! This provides better visibility in Port's UI, allowing you to:
- ✅ Track each endpoint's sync status individually.
- ✅ Debug mapping issues per endpoint.
- ✅ Monitor data ingestion per API call.
Example: Mapping two endpoints
resources:
# First endpoint: users
- kind: /api/v1/users
selector:
query: 'true' # JQ filter - 'true' means sync all entities
data_path: '.users' # Where to find the data array in the response
query_params: # Optional: add query parameters to the API call
active: "true"
department: "engineering"
port:
entity:
mappings:
identifier: .id
title: .name
blueprint: '"user"'
properties:
email: .email
department: .department
active: .is_active
created: .created_at
# Second endpoint: projects
- kind: /api/v1/projects
selector:
query: 'true'
data_path: '.data.projects' # Nested data extraction
query_params:
status: "active"
port:
entity:
mappings:
identifier: .project_id
title: .project_name
blueprint: '"project"'
properties:
description: .description
owner: .owner.email
budget: .budget_amount
created: .created_date
What each field does
kind: The API endpoint path (combined with your base URL).selector.query: JQ filter to include/exclude entities (use'true'to sync all).selector.data_path: JQ expression pointing to the array of items in the response.selector.query_params: (Optional) Query parameters added to the URL.selector.method: (Optional) HTTP method, defaults toGET.port.entity.mappings: How to map API fields to Port entity properties.
Advanced configurations
Once you have the basics working, these features handle more complex scenarios.
Nested endpoints
Fetch data from dynamic endpoints that depend on other resources.
Use case: Get all tickets, then fetch comments for each ticket.
How it works
Step 1 - Define parent endpoint:
resources:
- kind: /api/tickets
port:
entity:
mappings:
identifier: .id | tostring
blueprint: '"ticket"'
Step 2 - Define nested endpoint:
resources:
- kind: /api/tickets/{ticket_id}/comments
selector:
path_parameters:
ticket_id:
endpoint: /api/tickets
field: .id
filter: 'true'
port:
entity:
mappings:
identifier: .id | tostring
blueprint: '"comment"'
relations:
ticket: .ticket_id | tostring
The integration will:
- Call
/api/tickets→ Get ticket IDs [101, 102, 103]. - Call
/api/tickets/101/comments,/api/tickets/102/comments,/api/tickets/103/comments. - Sync all comments with relations to their parent tickets.
Real-world examples:
/projects/{project_id}/tasks- Tasks within projects./repositories/{repo_id}/pull-requests- PRs in repositories./customers/{customer_id}/orders- Orders for customers.
Pagination
For APIs that split data across multiple pages, configure how the integration fetches all pages.
Pagination types
Offset-based (like SQL):
GET /api/users?offset=0&limit=100
GET /api/users?offset=100&limit=100
Page-based (traditional):
GET /api/users?page=1&size=100
GET /api/users?page=2&size=100
Cursor-based (for large datasets):
GET /api/users?cursor=abc123&limit=100
GET /api/users?cursor=xyz789&limit=100
Custom parameter names
APIs often use different parameter names. You can configure:
- Pagination parameter: Use
skipinstead ofoffset, orafterinstead ofcursor. - Size parameter: Use
per_pageinstead oflimit, orpage_sizeinstead ofsize. - Start page: Specify if pages start at 0 or 1.
Example:
# GitHub uses page/per_page
paginationType: page
paginationParam: page
sizeParam: per_page
startPage: 1
# Stripe uses limit/starting_after
paginationType: cursor
paginationParam: starting_after
sizeParam: limit
Cursor path configuration
For cursor-based pagination, tell the integration where to find the next cursor in responses:
Example API response:
{
"data": [...],
"meta": {
"after_cursor": "xyz123",
"has_more": true
}
}
Configuration:
cursorPath: meta.after_cursor
hasMorePath: meta.has_more
Rate limiting
Control how the integration interacts with your API to prevent overwhelming it or hitting rate limits.
Request timeout
How long to wait for each API call to complete.
timeout: 30 # seconds (default: 30)
When to adjust:
- Increase for slow APIs or large responses (e.g., 60 seconds).
- Decrease for fast, local APIs (e.g., 10 seconds).
For advanced configuration such as proxies or self-signed certificates, click here.