Test webhooks locally like Stripe CLI

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

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)

Bash
npm install -g @modelriver/cli

From npm (Using npx)

No installation required — run commands directly:

Bash
npx @modelriver/cli listen --print

From Source

Bash
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:

Bash
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:

Bash
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:

Bash
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

Bash
modelriver login

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

Environment Variables

Set these environment variables for convenience:

Bash
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:

JSON
1{
2 "api_key": "mr_live_YOUR_API_KEY",
3 "api_url": "https://api.modelriver.com",
4 "forward_url": "http://localhost:4000/webhook/modelriver"
5}

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

Commands

modelriver login - Interactive Setup

Configure your API key and forward URL interactively.

Usage:

Bash
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:

Bash
# 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:

Bash
# 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:

Bash
# 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:

Bash
# 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:

Bash
# List webhooks
modelriver webhook list
 
# Verbose output
modelriver webhook list --verbose

modelriver webhook verify - Verify Signature

Verify a webhook signature locally.

Usage:

Bash
# 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)

Bash
# 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

Bash
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

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

Example 4: Forward Webhooks to Localhost

Bash
# 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:

JSON
1{
2 "channel_id": "uuid",
3 "timestamp": 1234567890,
4 "data": {
5 "status": "success|error",
6 "data": { ... },
7 "meta": { ... }
8 }
9}

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:

JSON
1{
2 "api_key": "mr_live_YOUR_API_KEY",
3 "api_url": "https://api.modelriver.com",
4 "forward_url": "http://localhost:4000/webhook/modelriver"
5}

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:

Bash
npm test

Tests cover critical components including:

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

Next Steps