Developer Guide · Recipes

Recipe: e-commerce backend

Connect a custom store backend to Inboxi: order lifecycle messages on WhatsApp, delivery receipts flowing back to your system, order history for the AI agent, and abandoned-cart reminders.

If your store runs on Salla or Shopify, use the ready-made integrations (Salla, Shopify), which cover orders and abandoned carts without code. This recipe is for a custom backend: you call Inboxi when the order changes, and Inboxi tells you when messages are delivered or fail.

Architecture

Order service
created → confirmed → shipped → delivered
trigger
Inboxi events
order.* templates on WhatsApp
deliver
Customer
Gets updates, can reply
receipts
Your webhook
delivered / read / failed

Set up

  1. 1
    Connect WhatsApp
    Connect your WhatsApp Business number in Settings › Channels.
  2. 2
    Configure order events
    In Settings › Automated Messages › Orders, configure order.created, order.confirmed, order.shipped and order.delivered: a session message and an approved Utility template for each, then switch them on.
  3. 3
    Create a custom cart event
    Click New Custom Event and create custom.cart_reminder with variables customer_name and cart_link, plus a template with a URL button mapped to cart_link.
  4. 4
    Create a key and a webhook
    Create an API key, then a webhook for message.delivered, message.read and message.failed pointing at your backend.

Order lifecycle messages

Trigger one event per state change from your order service. Keep the order in external data too, so the AI agent can answer “where is my order?”.

javascript
const EVENTS = {
  created:   'order.created',
  confirmed: 'order.confirmed',
  shipped:   'order.shipped',
  delivered: 'order.delivered'
};

async function onOrderStatusChanged(order) {
  // 1. Keep the AI agent and the inbox up to date
  await inboxi.post('/external-data', {
    source: 'store',
    dataType: 'orders_detail',
    contactIdentifier: order.customer.phone,           // international digits
    externalId: `order_${order.id}`,
    data: {
      order_number: order.number,
      status: order.status,
      total: `${order.total} ${order.currency}`,
      items: order.items.map(i => `${i.qty} × ${i.name}`),
      tracking_url: order.trackingUrl || null
    }
  });

  // 2. Message the customer
  const event = EVENTS[order.status];
  if (!event) return;
  const { data } = await inboxi.post('/events/trigger', {
    event,
    phone: order.customer.phone,
    data: {
      customer_name: order.customer.firstName,
      order_number: order.number,
      total_amount: `${order.total} ${order.currency}`,
      tracking_number: order.trackingNumber
    }
  });
  await Orders.saveNotification(order.id, event, data.logId);   // keep the logId
}
The four order.* events require customer_name and order_number. Optional fields such as total_amount and tracking_number are available to your message and template mapping.

Delivery status back into your backend

Store the WhatsApp outcome on the order so your support team (and your own dashboards) know whether the customer was reached.

javascript
app.post('/inboxi/webhook', verifyInboxi, async (req, res) => {
  res.sendStatus(200);                                   // acknowledge fast
  const { event, data } = req.body;

  if (event === 'message.delivered' || event === 'message.read') {
    await Notifications.markByPhone(data.to, event.split('.')[1], data.timestamp);
  }

  if (event === 'message.failed') {
    // e.g. the number is not on WhatsApp: fall back to SMS or email
    await Notifications.markByPhone(data.to, 'failed', data.timestamp, data.error);
    await fallbackToEmail(data.contact?.email, data.to);
  }
});

verifyInboxi is the signature check from Webhooks. Handle duplicates: a retried delivery carries the same messageId and status. To check one specific trigger instead, poll GET /api/v1/events/messaging/:logId/status with the saved logId.

Abandoned-cart reminders

Schedule the reminder when a cart is created, and cancel it on your side if the customer checks out first.

javascript
async function onCartUpdated(cart) {
  if (!cart.customer?.phone || cart.reminderScheduled) return;

  const sendAt = new Date(Date.now() + 60 * 60 * 1000).toISOString();   // in 1 hour
  const { data } = await inboxi.post('/events/trigger', {
    event: 'custom.cart_reminder',
    phone: cart.customer.phone,
    data: { customer_name: cart.customer.firstName, cart_link: `https://shop.example.com/cart/${cart.token}` },
    sendAt
  });
  await Carts.update(cart.id, { reminderScheduled: true, reminderLogId: data.logId });
}
Respect consent
Cart reminders are marketing-style messages. Only send them to customers who opted in, use a template in the correct Meta category, and keep the frequency low. A scheduled send cannot currently be cancelled through the API, so prefer a short delay and check the cart in your own job before triggering if your checkout rate is high.

Let support and the AI handle replies

  • Customer replies to order messages land in the same WhatsApp conversation in the inbox, with the order data in the side panel.
  • Register a GET remote action such as get_order_status (callback https://api.example.com/orders/{order_number}) and name it in your AI agent's instructions so it can fetch live tracking. See live lookups.
  • Register write actions like resend_invoice or cancel_order for agents to run from Settings › Developer Hub › Remote Actions.

Go-live checklist

CheckWhy
Every order event has an approved templateMost order updates are sent outside the 24-hour window.
Phones are stored in international formatLocal formats are not deliverable.
Webhook signature and timestamp are verifiedPrevents forged delivery updates.
Triggers are retried only on 429/5xxAvoids duplicate messages to customers.
One API key per environmentLets you rotate staging without touching production.