Voyager is a multi-tenant server that proxies calls to LinkedIn’s internal Voyager API and Sales Navigator API on behalf of AI agents. Your agent calls Voyager over REST (or MCP); Voyager forwards the call to LinkedIn using either your real Chrome session (via a WebSocket relay) or a direct server-side HTTP call through a residential proxy.
GET /api/agent/capabilities returns a structured catalogue of every endpoint, parameter, and response shape. GET /api/llms.txt is the plain-text equivalent for LLMs. GET /api/openapi.json is the OpenAPI 3.x spec.A session is an authenticated LinkedIn connection. You provide cookies from your LinkedIn browser session (easiest: install the Chrome extension, which auto-syncs them). Voyager stores them server-side and forwards them on every call — either via the extension relay or directly. Background session health checks only pause a user on genuine auth signals (HTTP 401/403); transient 5xx or network blips never cause an auto-pause.
Each organization is a tenant. A tenant can host multiple LinkedIn accounts. Tenants are isolated — separate cookies, rate meters, and data directories. API keys are tenant-scoped.
Within a tenant, each LinkedIn account is a user identified by a userId string (e.g. "charis", "harry"). The X-User-Id header routes a request to the correct LinkedIn session. Single-user tenants can omit the header — Voyager defaults to the only user.
Tenant-scoped API keys (voy_ prefix) authenticate requests. Each key is bound to a specific tenant; the X-User-Id header picks which user within the tenant. Keys are created, rotated, and revoked via the dashboard or POST /api/keys.
A few long-running operations (bulk employee export, deep company dossier, batch reads) return 202 Accepted with a jobId. Poll GET /api/jobs/:jobId until the job completes. See Async Jobs.
Instead of polling for new messages or connection requests, configure webhooks to receive real-time events (message_received, message_seen, connection_received, session_expired, etc.). Voyager signs payloads with HMAC-SHA256 and can auto-format messages for Slack. See Webhooks.
Every JSON endpoint returns the same top-level shape:
On failure, success is false, statusCode reflects the HTTP status, and errors is an array of structured error objects — each with message, code, statusCode, retryable, and action:
Every endpoint’s data lives under data. If you’re migrating from an older client that accessed res.profile directly, change it to res.data.profile.
Voyager does not enforce rate limits on outbound LinkedIn calls. It records and reports usage — messages sent, connections requested, profiles viewed, account age, seconds since last action — so your orchestrating agent has the full context (campaign strategy, account trust score, test vs. production) to decide policy. If you genuinely want a throttle, impose it in the agent. See Rate Limiting.
LinkedIn deprecates internal APIs without notice. Voyager tries multiple strategies per operation:
application/vnd.linkedin.normalized+json+2.1) for shape-sensitive endpointsIf strategy 1 fails, Voyager automatically tries strategy 2. Query IDs are pinned in tests against live captures so rotation fails loudly instead of silently serving stale data.
Transient transport failures — HTTP 429, any 5xx, "Relay connection closed", network errors — get retried with 2s then 4s backoff. Sustained auth-expiry signals (401/403 with authwall / checkpoint markers) auto-pause the user via the RiskMonitor. Nothing else does. A Railway redeploy that momentarily drops the WebSocket will not flip a user to paused.