Skip to content
Last updated Give Feedback

Creating a Plugin

import { Steps } from ‘@astrojs/starlight/components’;

This guide walks you through building a plugin that sends a Slack notification when a new order is paid.

  • ecommus running locally (see Quick Start)
  • Basic TypeScript knowledge
  1. Create the plugin folder

    Terminal window
    mkdir plugins/slack-notify
    cd plugins/slack-notify
  2. Create package.json

    {
    "name": "@ecommus/plugin-slack-notify",
    "version": "1.0.0",
    "type": "module",
    "main": "src/index.ts",
    "ecommus": {
    "name": "slack-notify",
    "version": "1.0.0",
    "description": "Send Slack notifications on order events",
    "author": "Your Name",
    "permissions": ["events.subscribe"],
    "settingsSchema": {
    "webhookUrl": {
    "label": "Slack Webhook URL",
    "type": "string",
    "required": true,
    "placeholder": "https://hooks.slack.com/services/..."
    },
    "channel": {
    "label": "Channel",
    "type": "string",
    "default": "#orders",
    "placeholder": "#orders"
    }
    }
    }
    }
  3. Create src/index.ts

    import type { PluginInit } from "@ecommus/plugin-sdk";
    const init: PluginInit = async (ctx) => {
    ctx.registerHook("order.paid", async (event) => {
    // Load settings for the current tenant
    const settings = await ctx.db.query.settings.findFirst({
    where: (s, { and, eq }) =>
    and(
    eq(s.tenantId, event.tenantId),
    eq(s.key, "plugin:slack-notify:settings")
    ),
    });
    if (!settings?.value) return;
    const { webhookUrl, channel } = settings.value as Record<string, string>;
    if (!webhookUrl) return;
    const { orderId, total, currency } = event.payload;
    await fetch(webhookUrl, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
    text: `New order paid: #${orderId}${total} ${currency} ${
    channel ?? ""
    }`.trim(),
    }),
    });
    ctx.logger.info({ orderId }, "Slack notification sent");
    });
    };
    export default init;
  4. Restart the API server

    The plugin loader runs at startup. Stop and restart node scripts/dev.mjs to pick up the new plugin.

    You should see in the logs:

    [plugin-loader] Loaded: slack-notify v1.0.0
  5. Configure settings in the admin

    Navigate to Admin → Integrations → slack-notify → Settings and enter your Slack webhook URL.

    The form is auto-generated from the settingsSchema you defined in package.json.

  6. Test it

    Create and pay for a test order. You should receive a Slack message.

plugins/my-plugin/
├── package.json ← manifest (required)
├── src/
│ └── index.ts ← PluginInit export default (required)
├── README.md ← optional docs
└── tests/
└── my-plugin.test.ts ← optional tests
  • Import types from @ecommus/plugin-sdk — it’s a pure type package with no runtime overhead
  • The init function can be async — await any setup operations
  • Use ctx.logger instead of console.log for structured logging
  • Access the database with ctx.db — the full Drizzle instance

If you want to publish your plugin as an npm package:

  1. Set "publishConfig": { "access": "public" } in package.json
  2. Follow our versioning policy (SemVer)
  3. Tag your package with ecommus-plugin on npm for discoverability