Automate Shopify Order & Return Alerts with OpenClaw AgentSkills
Running an e-commerce business means staying on top of every order and return. Delays in processing can lead to unhappy customers. In this guide, we'll walk you through building a custom OpenClaw AgentSkill that automatically polls your Shopify store every 30 minutes for new activity and sends instant alerts to WhatsApp and Telegram.
By the end of this tutorial, you will have a fully functional Node.js automation script integrated into the OpenClaw framework, ensuring your support and fulfillment teams never miss a beat.
What are Agent Skills?
Agent Skills is a simple, open format for giving agents new capabilities and expertise. They are folders containing instructions (SKILL.md), scripts, and resources that agents can discover and use to perform tasks more accurately and efficiently.
OpenClaw fully embraces this standard, which was originally developed by Anthropic. This means you can build a skill once and potentially use it across a growing ecosystem of compatible tools like VS Code, Cursor, Claude, Roo Code, and OpenClaw.
Why use Agent Skills?
Agents are increasingly capable but often lack the specific context to do real work reliably. Skills solve this by giving agents access to procedural knowledge and system-specific context on demand.
- Domain Expertise: Package specialized knowledge (e.g., your specific Shopify return policies) into reusable instructions.
- New Capabilities: Give agents the ability to interface with external systems, like calling the Shopify API or sending Telegram messages.
- Repeatable Workflows: Turn multi-step tasks into consistent, auditable actions.
In this tutorial, we are building a Shopify Order & Return Skill—effectively teaching your OpenClaw agent the specific "domain expertise" needed to monitor your store and alert your team.
Why Automate Shopify Alerts with OpenClaw?
OpenClaw provides a powerful, secure framework for running "AgentSkills"—specialized tasks that AI agents can execute. Instead of relying on rigid, expensive SaaS connectors (like Zapier or Make), writing your own skill allows for:
- Zero limits: Poll as often as you need without "task" quotas.
- Custom Logic: Filter orders, format messages exactly how you want, or check for specific fraud indicators.
- Multi-Channel Alerts: Send notifications to WhatsApp, Telegram, Slack, or email simultaneously.
What You'll Build
We will create a skill named shopify-order-returns-puller that performs the following actions:
- Polls the Shopify Admin API for orders and returns created in the last 30 minutes.
- Maintains State: Keeps track of the last processed ID to prevent duplicate alerts.
- Sends Notifications: Pushes formatted summaries to WhatsApp (via Business API) and Telegram.
- Runs on Schedule: Uses OpenClaw's Cron system to execute automatically.
Prerequisites
Before diving into the code, ensure you have:
- OpenClaw installed and configured.
- Node.js 22+ (required for top-level await and modern fetch features).
- A Shopify Admin API Access Token with read_orders and read_returns scopes.
- Configured WhatsApp/Telegram channels in OpenClaw.
Step 1: Directory Structure
Organize your skill files cleanly. We recommend the following standard layout for OpenClaw skills:
1shopify-order-returns-puller/ 2├── SKILL.md 3├── scripts/ 4│ └── poll_shopify.js 5├── references/ 6│ └── state.json 7└── README.md
- scripts/: Contains the actual Node.js logic.
- references/: Stores the diverse state file (JSON) to track processed orders.
Step 2: The Polling Logic (Node.js)
Create a file named scripts/poll_shopify.js. This script will connect to Shopify, check for new data, and output a notification payload that OpenClaw agents can interpret.
Copy the code below:
1// scripts/poll_shopify.js 2// Usage: set env SHOP_DOMAIN, SHOPIFY_ADMIN_TOKEN, OPENCLAW_NOTIFY_TARGETS (JSON array of channels/targets) 3 4import fs from 'fs/promises'; 5import https from 'https'; 6 7const SHOP = process.env.SHOP_DOMAIN; // e.g. 'myshop.myshopify.com' 8const TOKEN = process.env.SHOPIFY_ADMIN_TOKEN; 9const STATE_FILE = process.env.STATE_FILE || './references/state.json'; 10const NOTIFY = process.env.OPENCLAW_NOTIFY_TARGETS || '[]'; 11 12if (!SHOP || !TOKEN) { 13 console.error('Missing SHOP_DOMAIN or SHOPIFY_ADMIN_TOKEN'); 14 process.exit(2); 15} 16 17// Helper: Load the last seen IDs to avoid duplicates 18async function loadState() { 19 try { 20 const raw = await fs.readFile(STATE_FILE, 'utf8'); 21 return JSON.parse(raw); 22 } catch (e) { 23 return { lastOrderId: null, lastReturnId: null }; 24 } 25} 26 27// Helper: Save the new max IDs 28async function saveState(state) { 29 await fs.writeFile(STATE_FILE, JSON.stringify(state, null, 2)); 30} 31 32// Helper: Basic HTTP GET wrapper for Shopify 33function shopifyGet(path) { 34 const options = { 35 hostname: SHOP, 36 path, 37 method: 'GET', 38 headers: { 39 'X-Shopify-Access-Token': TOKEN, 40 'Content-Type': 'application/json', 41 'Accept': 'application/json' 42 } 43 }; 44 45 return new Promise((resolve, reject) => { 46 const req = https.request(options, (res) => { 47 let data = ''; 48 res.on('data', c => data += c); 49 res.on('end', () => { 50 try { 51 // Robust error handling could go here 52 resolve({ status: res.statusCode, body: JSON.parse(data), headers: res.headers }); 53 } catch (err) { reject(err); } 54 }); 55 }); 56 req.on('error', reject); 57 req.end(); 58 }); 59} 60 61function summarizeOrders(orders) { 62 return orders.map(o => `🛒 Order #${o.id}\n📅 ${o.created_at}\n👤 ${o.customer?.first_name || 'Guest'}\n💰 ${o.total_price}`).join('\n\n'); 63} 64 65async function notify(text) { 66 // Output a JSON payload that the OpenClaw agent monitors specifically to route messages. 67 const payload = { notify: JSON.parse(NOTIFY), text }; 68 console.log(JSON.stringify(payload)); 69} 70 71async function main() { 72 const state = await loadState(); 73 74 // 1) Fetch recent orders (limit to last 20 for this polling interval) 75 const ordersPath = `/admin/api/2024-07/orders.json?limit=20&status=any&order=created_at%20desc`; 76 const ordersResp = await shopifyGet(ordersPath); 77 78 if (ordersResp.status !== 200) { 79 console.error('Failed to fetch orders', ordersResp.status); 80 process.exit(3); 81 } 82 83 const orders = ordersResp.body.orders || []; 84 85 // Filter for ONLY truly new orders based on ID comparisons 86 let newOrders = orders.filter(o => !state.lastOrderId || BigInt(o.id) > BigInt(state.lastOrderId)); 87 88 if (newOrders.length) { 89 const summary = `📢 *New Shopify Orders (${newOrders.length})*\n\n` + summarizeOrders(newOrders); 90 await notify(summary); 91 92 // Update local state to the highest ID found 93 state.lastOrderId = newOrders.reduce((max, o) => BigInt(o.id) > BigInt(max) ? o.id : max, state.lastOrderId || '0'); 94 } 95 96 // 2) Fetch returns (using the Returns endpoint if available on your plan) 97 try { 98 const returnsPath = `/admin/api/2024-07/returns.json?limit=20&order=created_at%20desc`; 99 const returnsResp = await shopifyGet(returnsPath); 100 if (returnsResp.status === 200) { 101 const returns = returnsResp.body.returns || []; 102 let newReturns = returns.filter(r => !state.lastReturnId || BigInt(r.id) > BigInt(state.lastReturnId)); 103 104 if (newReturns.length) { 105 const summary = `⚠️ *New Returns (${newReturns.length})*\n` + newReturns.map(r => `↩️ Return #${r.id} for Order #${r.order_id}`).join('\n'); 106 await notify(summary); 107 108 state.lastReturnId = newReturns.reduce((max, r) => BigInt(r.id) > BigInt(max) ? r.id : max, state.lastReturnId || '0'); 109 } 110 } 111 } catch (e) { 112 console.warn('Returns endpoint check failed (may not be available on this plan):', e.message); 113 } 114 115 await saveState(state); 116 console.log('Poll complete.'); 117} 118 119main().catch(err => { console.error(err); process.exit(1); });
Step 3: Configure the Skill in openclaw.json
To make your skill persistent and secure, you should configure it in your OpenClaw global configuration file (typically located at ~/.openclaw/openclaw.json). This centralized config allows you to inject secrets and environment variables directly into the skill's runtime without hardcoding them in scripts.
Add your skill to the skills.entries object:
1{ 2 "skills": { 3 "entries": { 4 "shopify-order-returns-puller": { 5 "enabled": true, 6 "env": { 7 "SHOP_DOMAIN": "your-shop.myshopify.com", 8 "SHOPIFY_ADMIN_TOKEN": "shpat_xxxxxxxxxxxxxxxxxxx", 9 "OPENCLAW_NOTIFY_TARGETS": "[{\"channel\":\"whatsapp\",\"to\":\"+15550101010\"},{\"channel\":\"telegram\",\"to\":\"-100123456789\"}]" 10 } 11 } 12 } 13 } 14}
Configuration Breakdown:
- enabled: Explicitly turns the skill on.
- env: Injects environment variables scoped only to this skill's execution.
- OPENCLAW_NOTIFY_TARGETS: A JSON string defining where alerts go. This abstraction lets you change notification channels (e.g., swapping a phone number) in the config without touching your code.
Step 4: Automate with Cron
Finally, schedule the skill. In the OpenClaw dashboard or via CLI, add a Cron Job to run this task every 30 minutes.
1{ 2 "name": "poll-shopify-order-returns", 3 "schedule": { "kind": "cron", "expr": "*/30 * * * *", "tz": "UTC" }, 4 "payload": { 5 "kind": "agentTurn", 6 "message": "Run shopify-order-returns poll job" 7 }, 8 "sessionTarget": "isolated", 9 "enabled": true 10}
The isolated session target ensures that each poll runs in a clean context, preventing memory leaks or state confusion between runs.
Best Practices & Security
- Secret Management: Never commit your SHOPIFY_ADMIN_TOKEN to git. Use OpenClaw's secret management to inject it at runtime.
- Rate Limiting: If your store has high volume, implement exponential backoff in your shopifyGet function to respect Shopify's API leaky bucket limits.
- Error Logging: Enhance the script to send "Error" notifications to a dedicated developer channel if the API token fails or expires.
By implementing this OpenClaw AgentSkill, you transform your team's responsiveness. Returns are flagged instantly, and high-value orders can trigger immediate VIP protocols.
Need help building complex automation for your enterprise? Tirnav Solutions specializes in custom OpenClaw and Agentic AI integrations. Get in touch today.



