BETAEndpoint launching soon. Start on networkr today. Your /connect will arm viralr the moment we open.
Documentation

API Reference

Everything you need to connect your site and start shipping platform-native posts, clips, and paid-ad creative. The same API powers networkr (SEO) and outboxr (email); one key covers all three surfaces.

Quick Start

Two ways to connect: the CLI (interactive) or the SDK (programmatic). Both produce the same final state and both arm the whole suite by default.

Option 1: CLI (recommended for first setup)
$ npx viralr init

# Auto-detects your framework, domain, and existing config
# Asks for domain, email, voice, platforms, ads, networkr + outboxr opt-in
# Connects your accounts and ships the first thread immediately
Option 2: SDK
npm install viralr

import Viralr from 'viralr'

const vr = new Viralr({ apiKey: 'vr_...' })

const site = await vr.connect({
  domain: 'mysite.com',
  email: 'me@company.com',
  surfaces: ['viralr', 'viralr-ads', 'networkr', 'outboxr'],
  platforms: ['x', 'linkedin', 'threads'],
  voice_preset: 'technical'
})

// First thread ships immediately
// Daily cadence starts on configured schedule

SDK Reference

const vr = new Viralr({ apiKey, baseUrl? })

// Connect a site (one-call onboarding, arms the suite)
await vr.connect({ domain, email, surfaces, platforms, ... })

// List your sites
await vr.sites()

// Get site detail with stats per surface
await vr.site(siteId)

// Update site config
await vr.update(siteId, { voice_id?, platforms?, ads?, ... })

// Generate a thread or post now
await vr.generate(siteId, { topic?, angle?, platforms? })

// Queue an ad creative
await vr.ads.queue(siteId, { network, budget, creative })

// Generation history
await vr.history(siteId)

// Disconnect a site
await vr.disconnect(siteId)

// System health (no auth)
await vr.health()

Connect Endpoint

The POST /api/connect endpoint is the one-call onboarding. It auto-creates an account (or joins an existing one by email), creates a voice profile, creates an author, registers your site, arms the surfaces you selected (viralr, viralr-ads, networkr, outboxr), starts the cadence, and fires the first thread immediately.

POST /api/connect
{
  "domain": "mysite.com",                              // required
  "email": "me@company.com",                           // required (groups sites)
  "surfaces": ["viralr", "viralr-ads", "networkr", "outboxr"],  // default: all four
  "platforms": ["x", "linkedin", "threads", "bluesky"], // organic socials
  "ads": {                                             // optional
    "networks": ["meta", "x", "linkedin"],
    "daily_budget": 25
  },
  "name": "My Site",                                   // optional
  "topics": ["AI", "DevOps"],                          // optional themes
  "voice_preset": "technical",                         // professional|casual|technical|founder
  "author_name": "Jane Dev",                           // optional
  "cadence": "daily"                                   // default: daily per platform
}
Response
{
  "success": true,
  "site_id": "mysite-com",
  "network_id": "fe09c250...",
  "voice_id": "a3b1...",
  "author_id": "c4d2...",
  "armed_surfaces": ["viralr", "viralr-ads", "networkr", "outboxr"],
  "oauth_redirects": {
    "x": "https://api.networkr.dev/oauth/x/...",
    "linkedin": "...",
    "meta": "..."
  },
  "first_thread": "generating now. Check history in ~2 minutes.",
  "message": "MySite is live. First thread generating now...",
  "digest": "Weekly digest sent to me@company.com every Monday"
}

REST API

Base URL: https://api.networkr.dev (suite backend).

Sites

POST/api/connect
One-call onboarding
GET/api/sites
List all sites
GET/api/sites/:id
Site detail + stats
PUT/api/sites/:id
Update site config
DELETE/api/sites/:id
Disconnect site

Posts + Threads

POST/api/sites/:id/posts/generate
Generate a post or thread now
POST/api/sites/:id/posts/start
Enable daily cadence
POST/api/sites/:id/posts/stop
Disable daily cadence
GET/api/sites/:id/posts/history
Generation history
GET/api/sites/:id/posts/preview
Dry-run topic selection

Platforms

GET/api/sites/:id/platforms
List connected platforms
POST/api/sites/:id/platforms
Add a platform (returns OAuth redirect)
DELETE/api/sites/:id/platforms/:name
Disconnect platform, revoke token

Paid Ads (viralr-ads)

POST/api/sites/:id/ads/queue
Queue ad creative
GET/api/sites/:id/ads
List running ad creatives
GET/api/sites/:id/ads/:creative_id
Ad detail + performance
POST/api/sites/:id/ads/:creative_id/pause
Pause ad creative

Topic Engine

GET/api/topics/research?q=...
Platform trend research
POST/api/topics/engine/trigger
Run topic engine now
GET/api/topics/engine/status
Topic queue status

Content Registry

GET/api/registry
All posts + threads
GET/api/registry/search?tags=...
Search
GET/api/registry/stats
Suite stats

Suite & Admin

GET/api/networks
List accounts
GET/api/orchestrator/latest
Latest health report
POST/api/orchestrator/trigger
Run orchestrator now
POST/api/digest/trigger
Send weekly digest now
GET/api/status
Full system status
GET/health
Health check (no auth)

Authentication

All /api/* endpoints require a bearer token:

Authorization: Bearer vr_your_api_key

The /health endpoint is public (no auth required). One key covers viralr, viralr-ads, networkr, and outboxr on the same account.

Self-Hosting

The entire suite engine runs as a single Docker container. Bring your own API keys. The same container serves all three surfaces.

docker-compose.yml
services:
  viralr:
    build: .
    container_name: viralr
    restart: unless-stopped
    ports:
      - "3002:3002"
    env_file:
      - .env
    volumes:
      - ./data:/app/data
      - ./assets/logos:/app/assets/logos
    healthcheck:
      test: ["CMD", "wget", "-qO-", "http://localhost:3002/health"]
      interval: 30s
      timeout: 5s
      retries: 3
Required environment variables
VIRALR_SECRET=your-bearer-token
ANTHROPIC_API_KEY=sk-ant-...        # or use OpenRouter only
OPENROUTER_API_KEY=sk-or-...

# Platform OAuth apps (only the ones you use)
X_CLIENT_ID=...
X_CLIENT_SECRET=...
LINKEDIN_CLIENT_ID=...
LINKEDIN_CLIENT_SECRET=...
META_APP_ID=...
META_APP_SECRET=...
# ... etc per platform

MAILJET_API_KEY=...                  # optional, for weekly digest
MAILJET_SECRET_KEY=...