LuaWebhook allows you to create HTTP endpoints that can receive events from external services like Stripe, Shopify, GitHub, or any other webhook-enabled platform.
import { LuaWebhook, User } from 'lua-cli';const paymentWebhook = new LuaWebhook({ name: 'payment-webhook', description: 'Handle Stripe payment events', execute: async (event) => { const { body } = event; // ⚠️ Webhooks have NO conversational context // MUST provide userId to notify users if (body?.type === 'payment_intent.succeeded') { const customerId = body.data?.object?.metadata?.customerId; if (customerId) { const user = await User.get(customerId); await user.send([{ type: 'text', text: '✅ Payment confirmed!' }]); } } return { received: true }; }});export default paymentWebhook;
No Conversational Context: Webhooks execute outside of user conversations. You MUST use User.get(userId) with an explicit userId. Always store the user ID in your payment/order metadata.
New in v3.0.0: HTTP webhooks for external integrations. Use with LuaAgent.
Webhooks are context-less: They’re triggered by external systems, not user conversations. Always store the Lua user ID in your payment/order metadata so you can notify the right user.
import { LuaWebhook, env, Orders, User } from 'lua-cli';const stripeWebhook = new LuaWebhook({ name: 'stripe-payment-webhook', description: 'Handle Stripe payment events', execute: async (event) => { const { body } = event; console.log('Stripe event:', body?.type); switch (body?.type) { case 'payment_intent.succeeded': const paymentIntent = body.data?.object; // Update order status const order = await Orders.getById(paymentIntent.metadata.orderId); if (order) { await order.updateStatus('CONFIRMED'); // Get user by ID from payment metadata const customerId = paymentIntent.metadata.customerId; const user = await User.get(customerId); // Notify the specific user await user.send([{ type: 'text', text: `✅ Payment confirmed! Order #${order.id} is being processed. Amount: $${paymentIntent.amount/100}` }]); } return { success: true, orderId: order?.id }; case 'payment_intent.payment_failed': const failed = body.data?.object; console.error('Payment failed:', failed); // Notify user of failure const failedCustomerId = failed.metadata.customerId; if (failedCustomerId) { const user = await User.get(failedCustomerId); await user.send([{ type: 'text', text: `❌ Payment failed: ${failed.last_payment_error?.message}. Please try again.` }]); } return { success: false, reason: failed.last_payment_error?.message }; default: console.log('Unhandled event type:', body?.type); return { received: true }; } }});export default stripeWebhook;
Important: Always store the user ID (customerId) in your payment metadata so webhooks can notify the correct user. Example: metadata: { customerId: user.id, orderId: order.id }
import { LuaWebhook, env, Data, User } from 'lua-cli';const shopifyOrderWebhook = new LuaWebhook({ name: 'shopify-order-webhook', description: 'Handle Shopify order events', execute: async (event) => { const { body } = event; const order = body; // Store order in custom data await Data.create('shopify-orders', { orderId: order.id, orderNumber: order.order_number, customer: order.customer, total: order.total_price, items: order.line_items, status: order.financial_status, customerId: order.customer.id, // Store customer ID createdAt: order.created_at }, `Order #${order.order_number} ${order.customer.email} ${order.total_price}`); // Notify specific customer using their ID const user = await User.get(order.customer.id); await user.send([{ type: 'text', text: `🛍️ Order #${order.order_number} confirmed!\n\nTotal: $${order.total_price}\nItems: ${order.line_items.length}\n\nWe'll send shipping updates soon!` }]); return { success: true, orderId: order.id, orderNumber: order.order_number, customerId: order.customer.id }; }});export default shopifyOrderWebhook;
Customer Identification: Map external customer IDs (Shopify, Stripe) to Lua user IDs. Store this mapping in your order/payment metadata for webhook notifications.
Webhooks can subscribe to platform events — currently, message delivery status updates from WhatsApp. When subscribed, your webhook’s execute function receives the event payload automatically.
Event subscriptions currently support WhatsApp status events. Additional channels may emit these events in the future.
Use Agents.invoke to delegate work to a conversational agent after receiving a webhook event. Pass the user ID from the event payload so the invocation runs in that user’s context (conversation history is stored). If no user ID is available, omit userId and the invocation runs without user identity (no conversation history).
import { LuaWebhook, Agents } from 'lua-cli';const orderShippedWebhook = new LuaWebhook({ name: 'order-shipped-webhook', description: 'Delegate shipment notifications to the notification agent', execute: async (event) => { const { orderId, customerId, trackingNumber } = event.body ?? {}; if (!customerId) { return { skipped: true, reason: 'no customerId in payload' }; } const result = await Agents.invoke('notification-agent', { prompt: `Order ${orderId} has shipped. Tracking: ${trackingNumber}. Notify the customer.`, userId: customerId, // runs as this user — history is stored }); return { notified: true, agentReply: result.text }; },});export default orderShippedWebhook;
Agents API Reference
Full documentation for Agents.invoke — options, output shape, error handling, and more examples