Skip to main content
Tutorial 12 min read

Build WhatsApp Order Management with OpenClaw & Groq

Build a WhatsApp order management system using OpenClaw as a webhook-driven backend. Complete tutorial with SKILL.md, Supabase RLS, Groq integration, and p

Originally published:

Dev.to by Simran Shaikh

What You'll Learn

This tutorial guides you through building DukanBot, a production-grade WhatsApp order management system for small retailers using OpenClaw as a triggered messaging engine. You'll learn how to architect OpenClaw as a backend microservice (not a chatbot), design culturally-specific AI prompts in SKILL.md, integrate webhook-driven messaging flows, secure multi-tenant data with Supabase Row Level Security, and deploy a real-world SaaS application for 12 million Indian kirana stores.

Prerequisites

  • Node.js 18+ and npm installed locally
  • OpenClaw installed globally (npm install -g openclaw@latest)
  • Supabase account (free tier sufficient) with PostgreSQL database initialized
  • WhatsApp Business Account with API credentials and webhook URL capability
  • Groq API key (free tier; request at console.groq.com)
  • Git and basic command-line familiarity
  • Basic understanding of: REST APIs, webhook patterns, authentication tokens, database schema design
  • Frontend framework knowledge (React/Vue/Svelte — the dashboard uses your preferred stack)

Step 1: Understanding the Architecture — Why OpenClaw as a Microservice?

Most OpenClaw deployments treat it as a conversational chatbot: user talks → AI responds → conversation continues. DukanBot inverts this pattern entirely. The store owner's dashboard is the UI; OpenClaw runs silently as a triggered execution layer in the background.

The flow: Dashboard → Webhook POST → OpenClaw → Groq LLaMA 3.3 70B → WhatsApp → Customer. This separation of concerns means:

  • Dashboard developers don't touch OpenClaw or WhatsApp API complexity
  • OpenClaw skill authors don't need Supabase schema knowledge
  • Each layer scales independently
  • Testing is isolated (mock the webhook, test the skill independently)

Why Groq specifically? Latency. When a store owner clicks "Send Confirmation," they expect instant visual feedback. Groq's LPU hardware returns ~180ms responses. Claude Haiku averages 800ms; GPT-4o-mini ~600ms. For a 2-3 sentence WhatsApp message, the speed difference is the difference between "feels instant" and "feels broken."

Step 2: Setting Up OpenClaw Locally

Install OpenClaw globally and initialize DukanBot's configuration:

npm install -g openclaw@latest
openclaw --version  # Verify installation
mkdir dukanbot-openclaw && cd dukanbot-openclaw
openclaw init

The init command prompts you to:

  • Select model: Choose Groq LLaMA 3.3 70B
  • Configure Groq API key: Paste your key from console.groq.com
  • Set webhook port: Default is 18789 (note this; you'll POST to localhost:18789/webhook)
  • Download/create SKILL.md: This is where DukanBot's behavior lives

OpenClaw generates an openclaw.json file with your configuration. Examine it:

Critical: Keep this file out of version control. Add to .gitignore: openclaw.json, .env.local, any file containing API keys.

Start the OpenClaw daemon:

openclaw start

You should see: OpenClaw webhook server listening on localhost:18789. Leave this running in a separate terminal.

Step 3: Writing the SKILL.md — The Behavioral Engine

SKILL.md is where OpenClaw learns what DukanBot should do. This is pure Markdown, not code. The model reads it and uses it to guide message generation.

Create SKILL.md in your OpenClaw directory with this structure:

---
name: dukanbot
description: Kirana store WhatsApp assistant. Sends order confirmations and payment reminders. Handles customer replies automatically. Powered by Groq LLaMA 3.3 70B Versatile.
---

# DukanBot — Kirana Store WhatsApp AI

You are DukanBot, a WhatsApp assistant for Indian kirana stores.
You run on Groq's ultra-fast LLaMA 3.3 70B model via OpenClaw.

## When webhook type is "confirmation":
Send WhatsApp to the "to" number using the "message" field.
Add a warm closing: "Aapka business humara garv hai 🙏"
Log: CONFIRMATION sent to [customer_name] for [store_name]

## When webhook type is "reminder":
Send WhatsApp to the "to" number using the "message" field.
Keep tone polite but clear — small business relationships matter.
Add: "Koi problem ho toh batayein — hum help karenge 🙏"
Log: REMINDER sent to [customer_name] for [store_name]

## When customers reply on WhatsApp:
- "paid" / "done" / "ho gaya" → "Shukriya! Payment received ✅🙏"
- "when" / "kab" / "ready" → "Aapka order prepare ho raha hai. Notification milegi jaldi!"
- "cancel" / "nahi chahiye" → Forward to store owner: "⚠️ Customer wants to cancel. Please respond."
- anything else → Summarize and forward to store owner

## Tone Rules:
- Always Hinglish (mix Hindi and English naturally)
- Never rude, never rushed — ye relationship business hai
- Use 🙏 for greetings and thanks
- Keep messages under 3 sentences
- Always include store name

## What you are:
- Framework: OpenClaw (open-source personal AI)
- Model: Groq LLaMA 3.3 70B Versatile (~200ms response)
- Channel: WhatsApp
- Purpose: Automate the boring parts so store owners focus on people

Why Hinglish? Indian kirana store customers communicate in Hinglish, not formal English. "Aapka business humara garv hai" (Your business is our pride) generates measurably warmer customer responses than "Thank you for your patronage." Specificity to a real culture isn't localization overhead — it's product quality.

The instructions must be clear enough that a language model can execute them reliably. Test by manually sending webhook payloads (Step 4) and observe the responses. Refine the SKILL.md language if outputs don't match your intent.

Step 4: Building the Webhook Integration

Your dashboard (frontend) needs to POST JSON to OpenClaw's webhook endpoint. Here's what the payload structure looks like:

For order confirmation:

POST http://localhost:18789/webhook
Content-Type: application/json


For payment reminder:

POST http://localhost:18789/webhook
Content-Type: application/json


From your dashboard backend (Node.js example):

async function sendConfirmation(orderId, customerPhone, storeName) {
  const payload = {
    type: "confirmation",
    to: customerPhone,
    message: `Order ${orderId} from ${storeName} is confirmed 🙏`,
    customer_name: customerPhone.slice(-10),
    store_name: storeName,
    order_id: orderId
  };

  const response = await fetch("http://localhost:18789/webhook", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(payload)
  });

  return response.json(); // Returns { status: "sent", logged: true }
}

Test this immediately: Use curl or Postman to send a test webhook. Verify that OpenClaw receives it, logs it, and (if WhatsApp is configured) sends the message. Watch the OpenClaw daemon logs for errors.

Step 5: Securing Multi-Tenant Data with Supabase RLS

If DukanBot serves multiple store owners, Row Level Security (RLS) is not optional. Without it, every store owner sees every other store's orders.

Create two tables in Supabase:

orders table:

CREATE TABLE orders (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id UUID REFERENCES auth.users(id),
  store_name TEXT NOT NULL,
  customer_phone TEXT NOT NULL,
  order_details JSONB,
  amount_due INT,
  status TEXT CHECK (status IN ('pending', 'confirmed', 'paid', 'cancelled')),
  created_at TIMESTAMP DEFAULT NOW(),
  updated_at TIMESTAMP DEFAULT NOW()
);

ALTER TABLE orders ENABLE ROW LEVEL SECURITY;

CREATE POLICY "Users can see their own orders"
  ON orders FOR SELECT
  USING (auth.uid() = user_id);

CREATE POLICY "Users can update their own orders"
  ON orders FOR UPDATE
  USING (auth.uid() = user_id);

Why this matters: The policy USING (auth.uid() = user_id) ensures that when Supabase queries orders, it automatically filters to only rows where the authenticated user's ID matches the user_id column. No additional WHERE clause needed in your application code. At the database level, one user literally cannot query another user's data.

Test this:

  • Sign in as store owner A, insert an order
  • Sign in as store owner B, query orders — should return zero rows (not A's order)
  • Sign in as A again, query orders — should see A's order

Step 6: Building the Dashboard Frontend

Your dashboard needs:

  • Orders list: Fetch from Supabase (RLS automatically filters)
  • Send Confirmation button: POST to OpenClaw webhook, show success/error toast
  • Send Reminder button: POST to OpenClaw webhook with reminder template
  • OpenClaw connection status: Check if webhook URL is reachable (health endpoint)
  • Settings tab: Webhook URL configuration, Groq API key validation

Health check endpoint: Add to your dashboard backend:

app.get("/api/openclaw-status", async (req, res) => {
  try {
    const response = await fetch("http://localhost:18789/health");
    if (response.ok) {
      return res.json({ status: "connected", latency: response.headers.get("x-response-time") });
    }
  } catch (err) {
    return res.json({ status: "disconnected", error: err.message });
  }
});

In your frontend, call this every 10 seconds to show a live connection indicator (green dot = connected, red dot = disconnected). If disconnected, show a banner: "OpenClaw not connected. Go to Settings to configure webhook URL."

Step 7: Testing the Complete Flow

Scenario: Store owner Sharma sends an order confirmation

  1. Sharma opens DukanBot dashboard, sees a pending order from customer Rahul
  2. Clicks "Send Confirmation" button
  3. Dashboard POSTs to localhost:18789/webhook with order JSON
  4. OpenClaw receives webhook, queries SKILL.md instructions
  5. Groq LLaMA 3.3 70B generates a Hinglish message with warm tone
  6. OpenClaw sends WhatsApp via Twilio to +919876543210
  7. Rahul receives: "Hello Rahul! Your order DKN-023 from Sharma Kirana worth ₹340 is confirmed 🙏 Aapka business humara garv hai 🙏"
  8. Dashboard shows green toast: "✓ Sent via OpenClaw"
  9. Order status updates to "confirmed" in Supabase

Testing checklist:

  • ☐ OpenClaw daemon is running
  • ☐ Groq API key is valid (test in OpenClaw dashboard)
  • ☐ WhatsApp Business Account is connected to Twilio
  • ☐ Supabase RLS policies are active
  • ☐ Dashboard backend can POST to localhost:18789/webhook
  • ☐ Customer phone numbers are in E.164 format (+91 prefix for India)
  • ☐ Messages under 3 sentences (WhatsApp best practice)

Troubleshooting

Webhook receives 404 or connection refused

OpenClaw daemon isn't running. Return to the terminal where you ran openclaw start. You should see listening on localhost:18789. If not, check that port 18789 is not blocked by a firewall.

Groq API returns "rate limit exceeded"

You've exceeded the free tier quota (typically 30 requests/minute). This won't happen in development unless you're load testing. In production, upgrade to Groq's paid tier or implement request queuing on your dashboard backend.

WhatsApp message not delivered

Check in order:

  1. Is the phone number in E.164 format? (+919876543210, not 9876543210)
  2. Is the Twilio account provisioned for the customer's country?
  3. Did the customer opt-in to receive WhatsApp messages from your Twilio number?
  4. Check Twilio logs for bounce/rejection reasons

Supabase queries return empty, but data exists

RLS is blocking the query. Verify:

  • User is authenticated (check auth.uid() is not NULL)
  • The user_id column in the row matches the authenticated user's ID
  • RLS policy uses correct syntax: USING (auth.uid() = user_id)

Debug by temporarily disabling RLS (danger: all data visible), inserting a test order, re-enabling RLS, then checking if the order is readable.

Dashboard shows "OpenClaw disconnected" even though daemon is running

Check that your dashboard backend can actually reach localhost:18789. If your dashboard and OpenClaw are on different machines (not localhost), update the webhook URL in settings. Verify firewall rules allow traffic on port 18789.

Best Practices

SKILL.md Maintenance

Keep SKILL.md single-purpose and under 500 lines. If it grows, you're adding too much behavior. Split into separate skills (e.g., dukanbot-orders.md, dukanbot-payments.md) and route webhooks accordingly.

Webhook Payload Design

Include all context the model needs: store name, customer name, order ID, amount. Never make the model infer context from missing data. This reduces hallucinations and makes logs auditable.

Error Handling

Every webhook should be idempotent. If OpenClaw receives the same payload twice (network retry), it should produce the same output without duplicate messages. Include an idempotency_key UUID in your payload and log it alongside the message.

Response Latency Monitoring

Log the time between webhook POST and message delivery. Track p50, p95, p99 latencies weekly. If Groq responses degrade, switch to a fallback model (Claude Haiku) or queue the request for async processing.

Tone Testing

Before shipping tone changes, test with real store owners. "Aapka business humara garv hai" resonated with Indian retailers. "Thank you for your patronage" didn't. Culture-specific language is a feature, not localization overhead.

Scaling Considerations

For 12 million stores:

  • Don't run OpenClaw on the same server as your dashboard. Use a separate inference service.
  • Implement request queuing (Redis + Bull) for reminders sent at scale ("Send All" button).
  • Cache SKILL.md compilation if using multiple OpenClaw instances.
  • Use Supabase connection pooling (PgBouncer) to prevent database exhaustion.

Next Steps

Phase 1 (Week 1): Get a single store owner using DukanBot locally. Gather feedback on message tone and button placement.

Phase 2 (Week 2-3): Deploy to production (Vercel for dashboard, Railway/Render for OpenClaw backend, Supabase managed DB). Test with 5-10 real store owners.

Phase 3 (Week 4+): Add features based on real usage: inventory sync, payment link generation, customer analytics, bulk reminder scheduling.

Join the openclaw-community to share what you build and learn from other builders.

Summary

DukanBot demonstrates that OpenClaw's true power isn't in replacing chatbots — it's in automating backend workflows. By treating OpenClaw as a webhook-driven microservice (not a conversational UI), you unlock architectural flexibility, testability, and the ability to serve millions of users with minimal infrastructure.

Key takeaways:

  • Architecture matters: Dashboard as UI, OpenClaw as execution layer, Supabase as data layer — clear separation enables independent scaling.
  • SKILL.md is powerful: Write clear, specific instructions in Markdown. The model reliably executes them without code.
  • Latency is UX: Groq's 180ms response times feel instant. This matters for mobile users and store owners on slow connections.
  • Security is not optional: Multi-tenant apps must implement RLS from day one, not as an afterthought.
  • Cultural specificity is a feature: Hinglish tone and ₹ formatting aren't localization — they're product quality for your actual users.

Original source: Dev.to article by Simran Shaikh (April 24, 2026). Demo: dukan-bot.netlify.app | GitHub: github.com/SimranShaikh/dukanbot

Share:

Original Source

https://dev.to/simranshaikh20_50/dukanbot-i-flipped-openclaw-inside-out-to-run-whatsapp-for-12-million-kirana-stores-3956

View Original

Last updated: