npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@jimiford/webex

v0.1.3

Published

OpenClaw channel plugin for Cisco Webex messaging

Readme

@jimiford/webex

OpenClaw channel plugin for Cisco Webex messaging. Enables your OpenClaw gateway to send and receive messages via Webex bots.

Features

  • Direct Messages (1:1): Send and receive private messages with users
  • Space/Room Messages: Communicate in Webex spaces and rooms
  • Attachments: Send files via public URLs
  • Adaptive Cards: Rich interactive message cards
  • Threaded Replies: Support for message threading
  • Webhook Integration: Real-time message reception
  • Automatic Retries: Configurable retry logic with exponential backoff
  • Message Normalization: Converts Webex messages to OpenClaw's envelope format

Installation

npm install @jimiford/webex

Prerequisites

1. Create a Webex Bot

  1. Go to Webex Developer Portal
  2. Sign in with your Webex account
  3. Navigate to My Webex AppsCreate a New App
  4. Select Create a Bot
  5. Fill in the bot details:
    • Bot Name: Your bot's display name
    • Bot Username: Unique identifier (e.g., [email protected])
    • Icon: Upload or select an icon
    • Description: Brief description of your bot
  6. Click Add Bot
  7. Important: Copy the Bot Access Token - you'll only see it once!

2. Set Up a Public Webhook URL

Your webhook endpoint must be publicly accessible. Options:

  • Production: Deploy to a cloud provider with HTTPS
  • Development: Use ngrok to expose localhost:
    ngrok http 3000

Configuration

import { createWebexChannel, WebexChannelConfig } from '@jimiford/webex';

const config: WebexChannelConfig = {
  // Required: Your Webex bot access token
  token: 'YOUR_BOT_ACCESS_TOKEN',

  // Required: Public URL for receiving webhooks
  webhookUrl: 'https://your-domain.com/webhooks/webex',

  // Required: Policy for handling direct messages
  // - 'allow': Accept DMs from anyone
  // - 'deny': Reject all DMs
  // - 'allowlisted': Only accept from specified users
  dmPolicy: 'allow',

  // Optional: List of allowed person IDs or emails (when dmPolicy is 'allowlisted')
  allowFrom: ['[email protected]', 'Y2lzY29zcGFyazov...'],

  // Optional: Secret for webhook signature verification
  webhookSecret: 'your-webhook-secret',

  // Optional: Custom API base URL (default: https://webexapis.com/v1)
  apiBaseUrl: 'https://webexapis.com/v1',

  // Optional: Maximum retry attempts (default: 3)
  maxRetries: 3,

  // Optional: Retry delay in ms (default: 1000)
  retryDelayMs: 1000,
};

Usage

Basic Setup

import { createWebexChannel } from '@jimiford/webex';

async function main() {
  // Create and initialize the channel
  const channel = createWebexChannel();
  await channel.initialize({
    token: process.env.WEBEX_BOT_TOKEN!,
    webhookUrl: process.env.WEBHOOK_URL!,
    dmPolicy: 'allow',
  });

  // Register webhooks with Webex
  await channel.registerWebhooks();

  // Register a message handler
  channel.onMessage(async (envelope) => {
    console.log('Received message:', envelope);

    // Echo the message back
    await channel.send({
      to: envelope.conversationId,
      content: { text: `You said: ${envelope.content.text}` },
    });
  });

  console.log('Webex channel ready!');
}

main().catch(console.error);

Sending Messages

// Send to a room
await channel.sendText('roomId', 'Hello, room!');

// Send markdown
await channel.sendMarkdown('roomId', '**Bold** and _italic_');

// Send direct message
await channel.sendDirect('[email protected]', 'Hello!');

// Reply in a thread
await channel.reply('roomId', 'parentMessageId', 'This is a reply');

// Send with full options
await channel.send({
  to: 'roomId',
  content: {
    text: 'Plain text fallback',
    markdown: '**Rich** content',
    files: ['https://example.com/image.png'],
  },
  parentId: 'threadParentId',
});

Handling Webhooks

Set up an HTTP endpoint to receive webhooks:

import express from 'express';
import { createWebexChannel } from '@jimiford/webex';

const app = express();
app.use(express.json());

const channel = createWebexChannel();

// Initialize channel (do this on startup)
await channel.initialize({
  token: process.env.WEBEX_BOT_TOKEN!,
  webhookUrl: 'https://your-domain.com/webhooks/webex',
  dmPolicy: 'allow',
  webhookSecret: process.env.WEBHOOK_SECRET,
});

// Webhook endpoint
app.post('/webhooks/webex', async (req, res) => {
  try {
    const signature = req.headers['x-spark-signature'] as string;
    const envelope = await channel.handleWebhook(req.body, signature);

    if (envelope) {
      // Process the message
      console.log('Message from:', envelope.author.email);
      console.log('Content:', envelope.content.text);
    }

    res.status(200).send('OK');
  } catch (error) {
    console.error('Webhook error:', error);
    res.status(500).send('Error');
  }
});

app.listen(3000);

OpenClaw Envelope Format

Incoming messages are normalized to this format:

interface OpenClawEnvelope {
  id: string;                    // Webex message ID
  channel: 'webex';              // Channel identifier
  conversationId: string;        // Room ID
  author: {
    id: string;                  // Person ID
    email?: string;              // Email address
    displayName?: string;        // Display name
    isBot: boolean;              // Always false (bot messages filtered)
  };
  content: {
    text?: string;               // Plain text content
    markdown?: string;           // Markdown content
    attachments?: Array<{
      type: 'file' | 'card';
      url?: string;              // File URL
      content?: unknown;         // Card content
    }>;
  };
  metadata: {
    roomType: 'direct' | 'group';
    roomId: string;
    timestamp: string;           // ISO 8601
    mentions?: string[];         // Mentioned person IDs
    parentId?: string;           // Thread parent message ID
    raw: WebexMessage;           // Original Webex message
  };
}

Advanced Usage

Direct Sender Access

const sender = channel.getSender();

// Get message details
const message = await sender.getMessage('messageId');

// Delete a message
await sender.deleteMessage('messageId');

Direct Webhook Handler Access

const webhookHandler = channel.getWebhookHandler();

// List existing webhooks
const webhooks = await webhookHandler.listWebhooks();

// Delete a webhook
await webhookHandler.deleteWebhook('webhookId');

Error Handling

import { WebexApiRequestError } from '@jimiford/webex';

try {
  await channel.send({ to: 'invalid', content: { text: 'test' } });
} catch (error) {
  if (error instanceof WebexApiRequestError) {
    console.error('API Error:', error.message);
    console.error('Status:', error.statusCode);
    console.error('Tracking ID:', error.trackingId);
  }
}

API Reference

WebexChannel

| Method | Description | |--------|-------------| | initialize(config) | Initialize with configuration | | send(message) | Send a message | | sendText(roomId, text) | Send plain text to a room | | sendMarkdown(roomId, md) | Send markdown to a room | | sendDirect(to, text) | Send direct message | | reply(roomId, parentId, text) | Send threaded reply | | handleWebhook(payload, sig?) | Process incoming webhook | | onMessage(handler) | Register message handler | | offMessage(handler) | Remove message handler | | registerWebhooks() | Register webhooks with Webex | | shutdown() | Cleanup and shutdown |

Environment Variables

Recommended environment variables:

WEBEX_BOT_TOKEN=your_bot_access_token
WEBHOOK_URL=https://your-domain.com/webhooks/webex
WEBHOOK_SECRET=your_webhook_secret

Troubleshooting

Bot not receiving messages

  1. Ensure webhooks are registered: await channel.registerWebhooks()
  2. Verify your webhook URL is publicly accessible
  3. Check that the bot is added to the room/space
  4. For DMs, the user must message the bot first

"Invalid webhook signature" errors

  1. Ensure webhookSecret matches the secret used when creating webhooks
  2. Verify the signature header name: x-spark-signature

Rate limiting

The plugin includes automatic retry with exponential backoff for rate-limited requests. Adjust maxRetries and retryDelayMs in config if needed.

Security Considerations

When connecting a Webex bot to OpenClaw, keep these security implications in mind:

Access Control

  • DM Policy: The dmPolicy setting controls who can interact with your bot:
    • allow: Anyone can message the bot and receive responses (use with caution)
    • deny: The bot won't respond to direct messages
    • allowlisted: Only users in the allowFrom list receive responses
  • Recommendation: Use allowlisted in production and explicitly specify trusted users

Bot Token Permissions

  • The bot access token can read messages sent to the bot and send replies
  • Keep your token secret — never commit it to version control
  • Rotate tokens periodically via the Webex Developer Portal

Webhook Security

  • Always use a webhook secret in production to verify incoming requests
  • The webhookSecret enables HMAC-SHA1 signature verification
  • Without verification, attackers could send fake webhook payloads to your endpoint

Network Exposure

  • Your webhook endpoint must be publicly accessible for Webex to deliver messages
  • Use HTTPS in production (required by Webex)
  • Consider IP allowlisting if your infrastructure supports it
  • For development, tools like ngrok create temporary public URLs

OpenClaw Agent Access

  • Messages received by the bot flow through your OpenClaw agent
  • The agent has access to whatever tools you've configured (file access, web browsing, etc.)
  • Treat bot conversations with the same security considerations as direct OpenClaw access
  • Review your agent's tool permissions and workspace access

Best Practices

  1. Start with dmPolicy: 'deny' or dmPolicy: 'allowlisted' and explicitly allow trusted users
  2. Always configure a webhookSecret for production deployments
  3. Monitor bot activity through Webex admin tools and OpenClaw logs
  4. Use separate bots for development and production environments
  5. Regularly audit the allowFrom list

License

MIT