Introduction
How Voyager Works
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.
Architecture
- Multi-tenant. Each tenant has one or more users; each user maps 1:1 to a LinkedIn account. Tenants are isolated — separate sessions, rate meters, and data directories. One Voyager instance handles dozens of tenants with hundreds of users.
- Pure HTTP. Every endpoint — Voyager, Sales Navigator, search, messaging, connections, engagement — is direct HTTP, no headless browser and no DOM scraping. Requests are either forwarded through the user’s extension relay or issued from the server with synced cookies. The entire Puppeteer stack (Chromium launch, stealth patches, DOM-only phantoms) was removed 2026-04-22.
- 2-tier fetch. Tier 1 is the extension relay — the request leaves your user’s real Chrome with real cookies and a real residential IP. Tier 2 is a direct server-side call that uses the synced cookies plus an IPRoyal residential proxy. If Tier 1 is unreachable, Tier 2 kicks in automatically; callers don’t see the difference.
- Self-healing. Each operation tries REST first, falls back to GraphQL with a captured query ID, and retries transient failures (429, 5xx, relay disconnects) with 2s/4s backoff. When LinkedIn rotates a query ID or shape, the nightly stress harness detects it within the hour and files a GitHub issue.
- Discoverable.
GET /api/agent/capabilitiesreturns a structured catalogue of every endpoint, parameter, and response shape.GET /api/llms.txtis the plain-text equivalent for LLMs.GET /api/openapi.jsonis the OpenAPI 3.x spec.
Key Concepts
Sessions
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.
Tenants
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.
Users
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.
API Keys
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.
Async Jobs
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.
Webhooks
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.
API Design Principles
Consistent Response Envelope
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.
Rate Limiting as Metering
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.
Multi-Strategy Fallbacks
LinkedIn deprecates internal APIs without notice. Voyager tries multiple strategies per operation:
- REST (fastest, most reliable)
- GraphQL with a live-captured query ID (fallback)
- Voyager normalized+json (
application/vnd.linkedin.normalized+json+2.1) for shape-sensitive endpoints
If 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.
Retry and Auto-Pause Discipline
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.