open-wa v5 is alpha. Use v4.76.0 for mature production systems unless you are validating v5.
The Client APIAPI ExplorerLicensing

@open-wa/plugin-sdk

SDK for building open-wa plugins — types, helpers, and the createPlugin() factory

Package Plugin Sdk Wally

Generated from packages/plugin-sdk/README.md by apps/docs/scripts/gen-workspace-readme-docs.js. Do not edit this page directly.

@open-wa/plugin-sdk

SDK for building open-wa plugins — types, helpers, and the createPlugin() factory.

Part of the @open-wa v5 monorepo.

A plugin runs inside the open-wa runtime and can listen to WhatsApp events, call WhatsApp methods through a transport-agnostic client, expose HTTP routes and dashboard pages, and register AI tools — all without owning the browser or session lifecycle yourself.

Install

pnpm add @open-wa/plugin-sdk

Minimal plugin

import { createPlugin } from '@open-wa/plugin-sdk';

function getTextMessage(message: unknown) {
  if (!message || typeof message !== 'object') return null;
  const candidate = message as { body?: unknown; from?: unknown };
  if (typeof candidate.body !== 'string' || typeof candidate.from !== 'string') {
    return null;
  }
  return { body: candidate.body, from: candidate.from };
}

export default createPlugin({
  meta: {
    name: 'greeting-bot',
    version: '1.0.0',
    description: 'Greets contacts with a welcome message',
  },
  init: async ({ client, logger }) => ({
    'message.received': async ({ message }) => {
      const msg = getTextMessage(message);
      if (!msg) return;
      if (msg.body === 'Hi') {
        await client.sendText(msg.from, '👋 Welcome! How can I help?');
        logger.info('Sent greeting', { from: msg.from });
      }
    },
  }),
});

Typed config

Pass a Zod schema as configSchema; it is validated before init() runs and the parsed value is passed as config. z is re-exported so you don't need to install Zod separately.

import { createPlugin, z } from '@open-wa/plugin-sdk';

const configSchema = z.object({
  greeting: z.string().default('👋 Welcome!'),
});

export default createPlugin<z.infer<typeof configSchema>>({
  meta: { name: 'greeting-bot', version: '1.0.0' },
  configSchema,
  init: async ({ config, client }) => ({
    'message.received': async ({ message }) => {
      // config.greeting is typed and validated
    },
  }),
});

defineConfig() is also available as a factory helper when you prefer it:

import { defineConfig } from '@open-wa/plugin-sdk';

export const config = defineConfig((z) =>
  z.object({ greeting: z.string().default('👋 Welcome!') }),
);

Export requirements

The runtime loads a plugin from a module's default export or a named plugin export. Both work:

export default createPlugin({ /* ... */ });
// or
export const plugin = createPlugin({ /* ... */ });

Loading a plugin

Plugins are referenced by npm package name, scoped name, or file path, and configured under pluginConfig keyed by the plugin's meta.name (not the package name):

export default {
  plugins: ['greeting-bot', './my-local-plugin'],
  pluginConfig: {
    'greeting-bot': { greeting: 'Hello!' },
  },
};

Documentation

Full authoring guide, hooks reference, security model, publishing, and worked examples are on the docs site:

Real reference plugins in this repo:

License

H-DNH V1.0 — Hippocratic + Do Not Harm

Wally the Walrus typing

Was this helpful?

Wally and his cute companion coffee mug are coding day and night to keep this up-to-date!

On this page