Docs

Test webhooks locally like Stripe CLI

Forward production webhooks to localhost, test WebSocket connections, and trigger async requests without exposing your local server.

Current section

CLI Tool

Updated

This week

Build time

Minutes, not hours

Overview

The ModelRiver CLI is a command-line tool for testing webhooks and WebSockets from live/production ModelRiver, similar to Stripe CLI. It allows you to:

  • Listen for webhooks via WebSocket (no public URL required)
  • Forward webhooks to localhost for development
  • Test WebSocket connections and receive real-time AI responses
  • Trigger async requests from the command line
  • Verify webhook signatures locally

Installation

From npm (Global Installation)

npm install -g @modelriver/cli

From npm (Using npx)

No installation required — run commands directly:

npx @modelriver/cli listen --print

From Source

git clone https://github.com/modelriver/modelriver-cli.git
cd modelriver-cli
npm install
npm link  # Makes `modelriver` command available globally

Quick Start

Step 1: Login (One-Time Setup)

Run the interactive login command to configure your API key and forward URL:

modelriver login

You'll be prompted for:

  • API Key: Your ModelRiver API key (starts with mr_live_ or mr_test_)
  • Forward URL: Where to forward webhooks (e.g., http://localhost:4000)

The URL will be automatically normalized to include /webhook/modelriver.

Example session:

ModelRiver CLI Login
─────────────────────
Configure your ModelRiver CLI credentials.

Enter your ModelRiver API key: mr_live_abc123...
Enter your webhook forward URL (e.g. http://localhost:4000/webhook/modelriver): http://localhost:4000

✓ Configuration saved!

Saved Configuration
───────────────────
✓ API Key: mr_live_abc123...
✓ Forward URL: http://localhost:4000/webhook/modelriver

Step 2: Start Forwarding

After login, simply run:

modelriver forward

That's it! Webhooks will be forwarded to your configured URL.

Command Aliases

For convenience, the CLI supports short aliases:

CommandAliasDescription
listenlListen for webhooks
forwardfForward using saved config
triggertSend async request
websocketwsTest WebSocket connection

Example:

modelriver l --print   # Same as: modelriver listen --print
modelriver f           # Same as: modelriver forward
modelriver t -w my-workflow -m "Hello"  # Same as: modelriver trigger ...

Configuration

modelriver login

This saves your configuration to ~/.modelriver/config.json.

Environment Variables

Set these environment variables for convenience:

export MODELRIVER_API_KEY=mr_live_YOUR_API_KEY
export MODELRIVER_API_URL=https://api.modelriver.com  # Optional, defaults to production

Config File

Create a config file at ~/.modelriver/config.json or .modelriverrc in your project:

{
  "api_key": "mr_live_YOUR_API_KEY",
  "api_url": "https://api.modelriver.com",
  "forward_url": "http://localhost:4000/webhook/modelriver"
}

Priority: CLI arguments > Environment variables > Config file > Defaults

Commands

modelriver login - Interactive Setup

Configure your API key and forward URL interactively.

Usage:

modelriver login

What it does:

  1. Prompts for API key
  2. Prompts for webhook forward URL
  3. Saves configuration to ~/.modelriver/config.json
  4. Displays saved configuration

modelriver forward - Quick Webhook Forwarding

Forward webhooks using your saved configuration.

Usage:

# Simple - uses saved config from login
modelriver forward

# Override port
modelriver forward --port 4001

# Verbose output
modelriver forward --verbose

Options:

  • --port <number> - Override the port in forward URL
  • --verbose - Show detailed logging
  • --api-key <key> - Override saved API key

modelriver listen - Receive Webhooks via WebSocket

Like Stripe CLI, receive webhook events directly via WebSocket - no public URL needed.

Usage:

# Start listening for webhooks (like `stripe listen`)
modelriver listen --print
# Or use alias: modelriver l --print

# Forward to local server
modelriver listen --port 3001 --print

# With custom API key
modelriver listen --api-key mr_live_YOUR_KEY --print

# Forward to external server (without starting local server)
modelriver listen --port 3002 --forward --print

How it works (like Stripe CLI):

  1. Authenticates with your API key
  2. Gets a secure WebSocket token (valid for 24 hours)
  3. Connects to ModelRiver via WebSocket
  4. Receives webhook events in real-time - no public URL or ngrok required!
  5. Optionally forwards to local server

Example Output:

✓ Connecting to ModelRiver...
✓ WebSocket connected
✓ Joined webhook channel

> Ready! Listening for webhook events
> User ID: user-id-123
> Channel: cli_webhooks:user-id-123
> Local port: 3001

> Press Ctrl+C to stop

[2026-01-07 15:20:30] Webhook received via WebSocket:
  Channel ID: abc-123-def
  Status: success
  Data: {"result": "..."}

Options:

  • --print - Print received webhooks to console
  • --port <number> - Local server port to forward to
  • --forward - Enable forwarding to local server
  • --api-key <key> - ModelRiver API key
  • --verbose - Show detailed logs

modelriver websocket - Test WebSocket Connection

Test WebSocket connections to production and receive real-time responses.

Usage:

# Test with workflow
modelriver websocket --workflow my-workflow --message "Hello from CLI"

# With custom payload
modelriver websocket --workflow my-workflow --payload '{"messages": [{"role": "user", "content": "Test"}]}'

# Connect to existing channel
modelriver websocket --channel-id abc-123 --project-id xyz-789

# Verbose output
modelriver websocket --workflow my-workflow --message "Test" --verbose

Example Output:

✓ Making async request...
✓ Request queued: abc-123-def

> Channel ID: abc-123-def
> Project ID: xyz-789

✓ Connecting to WebSocket...
✓ WebSocket connected
✓ Channel joined

> Waiting for response...

✅ Response received:
{
  "status": "success",
  "data": { ... },
  "meta": { ... }
}

Options:

  • --workflow <name> - Workflow to test
  • --message <text> - Simple text message
  • --payload <json> - Custom JSON payload
  • --channel-id <id> - Existing channel ID
  • --project-id <id> - Project ID
  • --verbose - Show detailed logs

modelriver trigger - Send Async Request

Send a test async request and get channel details.

Usage:

# Basic trigger
modelriver trigger --workflow my-workflow --message "Test message"

# With custom payload
modelriver trigger --workflow my-workflow --payload '{"messages": [...]}'

# Create webhook to receive response
modelriver trigger --workflow my-workflow --message "Test" --webhook-url https://webhook.site/your-id

# Print channel details
modelriver trigger --workflow my-workflow --message "Test" --print-channel

Example Output:

✓ Async request created

Channel Details
{
  "channel_id": "abc-123-def",
  "project_id": "xyz-789",
  "websocket_url": "wss://api.modelriver.com/socket",
  "websocket_channel": "ai_response:xyz-789:abc-123-def",
  "status": "pending"
}

> Use --webhook-url to automatically receive responses via webhook
> Or use "modelriver websocket" to connect and receive responses

Options:

  • --workflow <name> - Workflow name
  • --message <text> - Simple text message
  • --payload <json> - Custom JSON payload
  • --webhook-url <url> - Webhook URL for responses
  • --print-channel - Print channel details
  • --verbose - Show detailed logs

modelriver webhook list - List Webhooks

List all webhooks for your project.

Usage:

# List webhooks
modelriver webhook list

# Verbose output
modelriver webhook list --verbose

modelriver webhook verify - Verify Signature

Verify a webhook signature locally.

Usage:

# From file
modelriver webhook verify \
  --payload webhook.json \
  --signature abc123... \
  --timestamp 1234567890 \
  --secret your-webhook-secret

# From JSON string
modelriver webhook verify \
  --payload '{"channel_id": "...", "data": {...}}' \
  --signature abc123... \
  --timestamp 1234567890 \
  --secret your-webhook-secret

Options:

  • --payload <file|json> - Webhook payload
  • --signature <sig> - Signature to verify
  • --timestamp <ts> - Unix timestamp
  • --secret <secret> - Webhook secret

Usage Examples

Example 1: Listen for Webhooks (like Stripe CLI)

# Terminal 1: Start listening for webhooks via WebSocket
export MODELRIVER_API_KEY=mr_live_YOUR_KEY
modelriver listen --print

# Terminal 2: Trigger an async AI request
# Webhook events will appear in Terminal 1 via WebSocket (no public URL needed!)

Example 2: Test WebSocket Connection

export MODELRIVER_API_KEY=mr_live_YOUR_KEY
modelriver websocket --workflow my-workflow --message "Hello from CLI" --verbose

Example 3: Send Test Request and Get Channel Info

export MODELRIVER_API_KEY=mr_live_YOUR_KEY
modelriver trigger --workflow my-workflow --message "Test" --print-channel

Example 4: Forward Webhooks to Localhost

# One-time setup
modelriver login

# Start forwarding
modelriver forward

# Or with custom port
modelriver listen --port 3000 --forward --print

Webhook Payload Format

Webhooks are sent as HTTP POST requests with the following format:

Body:

{
  "channel_id": "uuid",
  "timestamp": 1234567890,
  "data": {
    "status": "success|error",
    "data": { ... },
    "meta": { ... }
  }
}

Headers:

  • X-ModelRiver-Signature: HMAC-SHA256 hex signature
  • X-ModelRiver-Timestamp: Unix timestamp string
  • X-ModelRiver-Webhook-Id: Webhook UUID
  • Content-Type: application/json

WebSocket Protocol

The CLI connects to ModelRiver WebSockets using the Phoenix protocol:

  1. Connect to wss://api.modelriver.com/socket?token={ws_token}
  2. Join channel: ai_response:{project_id}:{channel_id}
  3. Listen for response event containing the AI response

Troubleshooting

"API key is required"

Set the API key via:

  • Environment variable: export MODELRIVER_API_KEY=mr_live_YOUR_KEY
  • CLI flag: --api-key mr_live_YOUR_KEY
  • Config file: ~/.modelriver/config.json

"WebSocket connection failed"

  • Verify the API URL is correct
  • Check that the ws_token hasn't expired (24-hour limit for CLI tokens)
  • Check network connectivity
  • If using production, ensure you're using wss:// (secure WebSocket)

"Webhook signature verification failed"

  • Ensure the secret matches exactly (no extra spaces)
  • Verify timestamp is recent (within 5 minutes)
  • Check that payload structure matches expected format

Note: The CLI does not support creating permanent webhooks. Use the ModelRiver dashboard to create webhooks for production use. The CLI only creates temporary webhooks for testing (via listen and test-webhook commands), which are automatically cleaned up.

API Endpoints

The CLI uses these ModelRiver API endpoints:

  • POST /v1/ai/async - Create async request
  • POST /v1/ai - Create sync request
  • GET /v1/webhooks - List webhooks
  • WebSocket connection at wss://api.modelriver.com/socket

Configuration File Format

The CLI looks for configuration in these locations (in order):

  1. .modelriverrc in current directory
  2. ~/.modelriver/config.json in home directory

Example ~/.modelriver/config.json:

{
  "api_key": "mr_live_YOUR_API_KEY",
  "api_url": "https://api.modelriver.com",
  "forward_url": "http://localhost:4000/webhook/modelriver"
}

Security

  • API keys are stored locally in ~/.modelriver/config.json
  • WebSocket tokens are short-lived (24 hours for CLI usage)
  • Never commit config files with API keys to version control
  • Add ~/.modelriverrc and .modelriverrc to your .gitignore

Development

Running Tests

The CLI includes a Jest test suite. To run the tests:

npm test

Tests cover critical components including:

  • Webhook signature verification
  • Configuration loading
  • API client validation
  • Output formatting

Next Steps