Skip to main content

Overview

Tunnels represent active connections that expose services through agents. The Tunnels API provides programmatic equivalents to connect expose and connect reach CLI commands.

Create Tunnel

Create a new tunnel to expose a service (equivalent to connect expose).
curl -X POST https://api.privateconnect.co/v1/tunnels \
  -H "x-api-key: pc_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "target": "localhost:5432",
    "name": "prod-db",
    "protocol": "tcp",
    "agentId": "550e8400-e29b-41d4-a716-446655440000",
    "isPublic": false
  }'
Request Body:
target
string | object
required
Target service in host:port format, or object with host and port fields
agentId
string
required
UUID of the agent that will expose this service
name
string
Tunnel name (auto-generated if not provided). 1-100 characters.
protocol
string
default:"auto"
Protocol: auto, tcp, udp, http, https
isPublic
boolean
default:"false"
Make publicly accessible via generated URL
Response:
{
  "id": "tun_123",
  "name": "prod-db",
  "agentId": "550e8400-e29b-41d4-a716-446655440000",
  "targetHost": "localhost",
  "targetPort": 5432,
  "tunnelPort": 50123,
  "protocol": "tcp",
  "status": "active",
  "isPublic": false,
  "createdAt": "2026-03-02T10:00:00.000Z"
}
tunnelPort
number
Port on the hub where the tunnel is accessible

List Tunnels

Retrieve all active tunnels in the workspace.
curl https://api.privateconnect.co/v1/tunnels \
  -H "x-api-key: pc_your_api_key"
Response:
[
  {
    "id": "tun_123",
    "name": "prod-db",
    "agentId": "550e8400-e29b-41d4-a716-446655440000",
    "targetHost": "localhost",
    "targetPort": 5432,
    "tunnelPort": 50123,
    "protocol": "tcp",
    "status": "active",
    "isPublic": false,
    "createdAt": "2026-03-02T10:00:00.000Z"
  }
]

Get Tunnel Details

Retrieve details for a specific tunnel.
curl https://api.privateconnect.co/v1/tunnels/tun_123 \
  -H "x-api-key: pc_your_api_key"
Response:
{
  "id": "tun_123",
  "name": "prod-db",
  "agentId": "550e8400-e29b-41d4-a716-446655440000",
  "targetHost": "localhost",
  "targetPort": 5432,
  "tunnelPort": 50123,
  "protocol": "tcp",
  "status": "active",
  "isPublic": false,
  "publicUrl": null,
  "metadata": {},
  "createdAt": "2026-03-02T10:00:00.000Z",
  "lastActivityAt": "2026-03-02T10:05:00.000Z"
}

Update Tunnel

Update tunnel properties like name, status, or metadata.
curl -X PATCH https://api.privateconnect.co/v1/tunnels/tun_123 \
  -H "x-api-key: pc_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "production-database",
    "status": "active",
    "metadata": { "environment": "production" }
  }'
Request Body:
name
string
New tunnel name (1-100 characters)
status
string
Tunnel status: active or paused
metadata
object
Custom metadata (any JSON object)
Response:
{
  "id": "tun_123",
  "name": "production-database",
  "status": "active",
  "metadata": { "environment": "production" }
}

Delete Tunnel

Delete a tunnel (equivalent to revoking/closing the exposed service).
curl -X DELETE https://api.privateconnect.co/v1/tunnels/tun_123 \
  -H "x-api-key: pc_your_api_key"
Response:
{
  "success": true
}
Deleting a tunnel immediately closes all active connections. Any shares using this tunnel will stop working.

Connect to Tunnel

Initiate a connection to a tunnel (equivalent to connect reach).
curl -X POST https://api.privateconnect.co/v1/tunnels/tun_123/connect \
  -H "x-api-key: pc_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "agentId": "660e8400-e29b-41d4-a716-446655440001",
    "localPort": 5432
  }'
Request Body:
agentId
string
required
UUID of the agent that will receive the tunnel
localPort
number
Local port to bind (optional, uses target port if not specified)
Response:
{
  "success": true,
  "tunnel": {
    "id": "tun_123",
    "name": "prod-db",
    "targetHost": "localhost",
    "targetPort": 5432,
    "localPort": 5432,
    "tunnelPort": 50123
  },
  "connectionString": "postgres://localhost:5432/postgres",
  "message": "Tunnel active on port 50123"
}
connectionString
string
Connection string formatted for the detected protocol (PostgreSQL, MySQL, Redis, MongoDB, HTTP, or generic TCP)

Create Share for Tunnel

Create a shareable link for a tunnel (equivalent to connect share).
curl -X POST https://api.privateconnect.co/v1/tunnels/tun_123/share \
  -H "x-api-key: pc_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "contractor-access",
    "description": "Temporary access for external team",
    "expiresIn": "24h",
    "allowedMethods": ["GET", "POST"],
    "rateLimitPerMin": 100
  }'
Request Body:
name
string
required
Share name (1-100 characters)
description
string
Share description (max 500 characters)
expiresIn
string
default:"24h"
Expiration duration: 1h, 24h, 7d, 30d, never
allowedMethods
string[]
HTTP methods to allow (for HTTP/HTTPS tunnels). Example: ["GET", "POST"]
rateLimitPerMin
number
Rate limit per minute (1-1000)
Response:
{
  "id": "share_123",
  "token": "share_tok_1234567890abcdefghijklmnop",
  "name": "contractor-access",
  "expiresAt": "2026-03-03T10:00:00.000Z",
  "shareUrl": "https://link.privateconnect.co/shared/share_tok_1234567890abcdefghijklmnop"
}
Save the shareUrl - it’s the link you’ll send to users for accessing the tunnel.

Tunnel Status Values

Tunnels have the following status values:
  • active - Tunnel is running and accepting connections
  • paused - Tunnel exists but is not accepting connections
  • connecting - Tunnel is being established
  • error - Tunnel encountered an error

Connection Strings

The API automatically generates protocol-specific connection strings:
postgres://localhost:5432/postgres
mysql://localhost:3306
redis://localhost:6379
mongodb://localhost:27017
https://localhost:8443
tcp://localhost:50123

Use Cases

Database Access

Expose development or staging databases for team access without VPN.

API Testing

Share local APIs with external testers or clients.

Demo Environments

Create temporary tunnels for product demos.

CI/CD Integration

Programmatically create tunnels for automated testing pipelines.

Best Practices

  1. Use descriptive names - Name tunnels after their purpose: staging-api, prod-db-readonly
  2. Set appropriate TTLs - Use short-lived tunnels for temporary access, long-lived for permanent services
  3. Monitor usage - Use webhooks to track tunnel creation and deletion events
  4. Clean up - Delete tunnels when they’re no longer needed to reduce overhead
  5. Use shares - For external access, create shares with access control instead of making tunnels public

Build docs developers (and LLMs) love