SeloraXDEVELOPERS

Tutorial: Building SeloraX Messaging

Tutorial: Building SeloraX Messaging

This tutorial walks through the SeloraX Messaging app -- a production app that sends automated SMS messages to customers when order statuses change. It demonstrates every major platform feature: OAuth installation, iframe embedding, wallet billing, webhooks, and the full app lifecycle.

By the end, you will understand how all the pieces of the SeloraX app platform fit together.

What the App Does

When a merchant installs SeloraX Messaging:

  1. The merchant configures SMS templates for each order status (confirmed, processing, shipped, delivered)
  2. When an order's status changes, the platform fires a webhook to the app
  3. The app matches the status to a template, substitutes variables, debits the merchant's wallet, and sends the SMS

Architecture Overview

+-------------------+     postMessage      +---------------------+
| SeloraX Dashboard |<-------------------->| Messaging Frontend   |
| (parent window)   |   App Bridge         | (React, iframe)      |
+-------------------+                      +---------------------+
        |                                          |
        | REST API                                 | REST API
        v                                          v
+-------------------+                      +---------------------+
| SeloraX Platform  |--- webhooks -------->| Messaging Backend    |
| (Express API)     |   (Inngest)          | (Express server)     |
+-------------------+                      +---------------------+
                                                   |
                                                   | HTTP
                                                   v
                                           +---------------------+
                                           | BulkSMS API          |
                                           | (SMS delivery)       |
                                           +---------------------+

Components:

  • Frontend: React app embedded as an iframe in the merchant dashboard. Handles template management UI.
  • Backend: Express server handling OAuth callbacks, webhook processing, and SMS delivery.
  • Billing: Wallet-based model. Merchants top up their wallet; each SMS debits the balance.

Step 1: App Registration

Register your app on the SeloraX platform with the following configuration:

FieldValue
NameSeloraX Messaging
Slugselorax-messaging
Scopesread:orders, read:customers, read:store, billing, manage:messaging
Webhook topicsorder.status_changed
app_urlFrontend iframe URL (e.g., https://messaging.selorax.com)
webhook_urlBackend OAuth endpoint (e.g., https://messaging-api.selorax.com/api/messaging/oauth)

The platform assigns your app a client_id, client_secret, and session_signing_key. Store these securely.

Step 2: OAuth Installation

When a merchant clicks Install in the SeloraX marketplace:

  1. The dashboard initiates a direct-install flow (no redirect-based OAuth dance needed for first-party apps)
  2. The platform delivers access_token and refresh_token to your webhook_url
  3. Your backend stores these tokens associated with the store_id
  4. The platform automatically creates webhook subscriptions for the topics your app declared (order.status_changed)
// Your OAuth callback handler
router.post('/oauth', async (req, res) => {
  const { store_id, access_token, refresh_token, installation_id } = req.body;
 
  // Store credentials for this merchant
  await db.query(
    'INSERT INTO installations (store_id, access_token, refresh_token, installation_id) VALUES (?, ?, ?, ?)',
    [store_id, access_token, refresh_token, installation_id]
  );
 
  res.status(200).json({ message: 'Installation successful' });
});

Step 3: Iframe Embed

Once installed, the merchant accesses your app from their dashboard. The embedding flow uses the App Bridge and Session Token Flow:

  1. Dashboard fetches embed params from the platform (HMAC-signed iframe URL + session token)
  2. Dashboard loads your app in an iframe
  3. Your app verifies the HMAC parameters
  4. Your app sends app-bridge:ready
  5. Dashboard responds with selorax:session-token
  6. Your app initializes with the token and displays the template management UI
// In your React app's entry point
import { SeloraXAppBridge } from './app-bridge';
 
const bridge = new SeloraXAppBridge();
 
bridge.on('token', (token) => {
  // Store token, initialize app state
  localStorage.setItem('session_token', token);
  fetchTemplates(token);
});
 
bridge.ready();

Step 4: Wallet Setup

SeloraX Messaging uses wallet-based billing. The merchant pre-loads a balance, and each SMS debits from it.

Creating a Top-Up Charge

When the merchant clicks "Top Up Wallet" in your app:

// App backend creates a wallet top-up charge via client credentials
const response = await fetch('https://api.selorax.io/api/apps/v1/billing/wallet-topup', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-Client-Id': process.env.SELORAX_CLIENT_ID,
    'X-Client-Secret': process.env.SELORAX_CLIENT_SECRET,
    'X-Store-Id': String(storeId),
  },
  body: JSON.stringify({
    amount: 500.00,
    currency: 'BDT',
    return_url: `${process.env.APP_URL}/wallet/success`,
  }),
});
 
const result = await response.json();
const { charge_id } = result.data;

Redirecting to Payment

Use the App Bridge to navigate the merchant to the charge approval page:

bridge.billingRedirect(`/${storeId}/settings/apps/billing/${chargeId}`);

The merchant pays via EPS (Electronic Payment System). On successful payment, the wallet is credited automatically.

Checking Balance

Before sending an SMS, check the wallet balance:

const balanceRes = await fetch('https://api.selorax.io/api/apps/v1/billing/wallet', {
  headers: {
    'X-Client-Id': process.env.SELORAX_CLIENT_ID,
    'X-Client-Secret': process.env.SELORAX_CLIENT_SECRET,
    'X-Store-Id': String(storeId),
  },
});
 
const result = await balanceRes.json();
const { balance } = result.data;

Step 5: Template Configuration

The app's iframe UI lets merchants create SMS templates with placeholder variables:

Available template variables:

VariableDescriptionExample
{{order_number}}The order's display numberORD-1234
{{customer_name}}Customer's full nameJohn Doe
{{customer_phone}}Customer's phone number+8801712345678
{{tracking_id}}Shipping tracking IDTRACK123
{{store_name}}Merchant's store nameMy Shop
{{status}}New order statusconfirmed

Example templates by status:

  • Confirmed: Hi {{customer_name}}, your order #{{order_number}} has been confirmed! We will process it shortly.
  • Processing: Hi {{customer_name}}, your order #{{order_number}} is being prepared.
  • Shipped: Hi {{customer_name}}, your order #{{order_number}} has been shipped! Tracking: {{tracking_id}}
  • Delivered: Hi {{customer_name}}, your order #{{order_number}} has been delivered. Thank you for shopping with {{store_name}}!

Templates are stored in the messaging app's own database, mapped to order statuses.

Step 6: Webhook-Triggered SMS

This is the core of the app. When an order's status changes, the following chain executes:

6.1 Platform Emits Event

When a merchant (or the system) changes an order's status, the platform calls publishPlatformEvent() with the topic order.status_changed.

6.2 Inngest Delivers Webhook

Inngest picks up the event and fans it out to all apps subscribed to order.status_changed for that store. The webhook is delivered as an HMAC-signed HTTP POST to your app's webhook endpoint.

6.3 App Receives and Verifies

router.post('/webhooks', express.raw({ type: 'application/json' }), async (req, res) => {
  // Verify HMAC signature (signs timestamp.body to prevent replay attacks)
  const signature = req.headers['x-selorax-signature'];
  const timestamp = req.headers['x-selorax-timestamp'];
  const isValid = verifySignature(req.body, signature, timestamp, WEBHOOK_SECRET);
  if (!isValid) return res.status(401).send('Invalid signature');
 
  const event = JSON.parse(req.body);
  // Process...
});

6.4 Status Mapping

The platform emits a generic order.status_changed event. Your app maps the order's new status to a specific event topic using STATUS_TO_EVENT_TOPIC:

Order StatusMapped Topic
confirmedorder.confirmed
processingorder.processing
shippedorder.shipped
deliveredorder.delivered

6.5 Template Rendering and SMS Delivery

The app:

  1. Looks up the merchant's template for the mapped status
  2. Substitutes variables using the event payload (which includes customer_name, customer_phone, order_number, tracking_id, store_name via buildOrderEventPayload())
  3. Checks the merchant's wallet balance
  4. Debits the wallet for the SMS cost
  5. Sends the SMS via the BulkSMS API

See the Webhook to SMS guide for the complete code implementation.

Step 7: Ongoing Operations

Token Refresh

Server-to-server API calls use client_id + client_secret (these never expire, similar to Shopify offline tokens). Session tokens for the iframe are refreshed via the App Bridge on 401.

Wallet Low-Balance Alerts

Monitor wallet balance and alert merchants when it drops below a threshold:

if (balance < 50.00) {
  // Show low-balance warning in the iframe UI
  // Optionally send a notification to the merchant
}

SMS Delivery Logging

Log every SMS attempt with status, cost, and timestamp for merchant visibility:

await db.query(
  'INSERT INTO sms_logs (store_id, order_id, phone, status, cost, sent_at) VALUES (?, ?, ?, ?, ?, NOW())',
  [storeId, orderId, phone, 'sent', 2.50]
);

Step 8: Production Deployment

When your app is working locally, deploy it to production:

Backend Environment Variables

Set these on your backend server (e.g., DigitalOcean App Platform, Railway, Fly.io):

# App credentials (from Developer Portal)
SELORAX_CLIENT_ID=sx_app_...
SELORAX_CLIENT_SECRET=sx_secret_...
SESSION_SIGNING_KEY=...   # 64 hex chars, from Developer Portal
 
# Platform API
SELORAX_API_URL=https://api.selorax.io/api
 
# Database (your app's own database)
DATABASE_URL=mysql://user:pass@host:port/dbname
 
# SMS provider
SMS_API_KEY=your_sms_api_key
SMS_API_ENDPOINT=http://bulksmsbd.net/api/smsapi
 
# Server
PORT=5002
NODE_ENV=production
JWT_SECRET=your_jwt_secret

Frontend Environment Variables

Set these in your frontend deployment (e.g., Vercel):

NEXT_PUBLIC_MESSAGING_API_URL=https://your-backend.example.com/api/messaging

Update App URLs in Developer Portal

After deploying, update your app's URLs via the Developer Portal:

  1. Set app_url to your production frontend URL (e.g., https://messaging.selorax.com)
  2. Set webhook_url to your production backend OAuth endpoint (e.g., https://messaging-api.selorax.com/api/messaging/oauth)
  3. Set webhook_receive_url to your production webhook endpoint (e.g., https://messaging-api.selorax.com/api/messaging/webhooks)

Database Setup

  1. Ensure requested_scopes includes billing (required for wallet operations):
    -- Check current scopes
    SELECT requested_scopes FROM apps WHERE slug = 'your-app-slug';
  2. After installation, verify granted_scopes in app_installations also includes billing.

Verify Production

# 1. Check backend health
curl https://your-backend.example.com/api/messaging/health
 
# 2. Check wallet endpoint (requires valid session token)
# This should return the wallet balance, not 403 or 500
 
# 3. Install on a test store and verify:
#    - Iframe loads and shows "Connected"
#    - Wallet balance displays correctly
#    - Top Up button appears
#    - Templates save and load

Common production issues

  • Wallet/Top Up not showing: Missing billing scope in requested_scopes or granted_scopes. Add it via SQL and reinstall.
  • Iframe shows "Connecting...": Wrong app_url or DASHBOARD_URL mismatch. Verify both point to correct production URLs.
  • Webhook delivery fails: Wrong webhook_receive_url. Update via Developer Portal and verify with the webhook test endpoint.

Recap

This tutorial covered the full lifecycle of a SeloraX embedded app:

StepPlatform Feature
RegistrationApp manifest (scopes, topics, URLs) via Developer Portal
InstallationOAuth direct-install, token delivery
EmbeddingApp Bridge, session tokens, HMAC-signed URLs
BillingWallet top-up via EPS, per-action debits
ConfigurationIframe UI for merchant settings
AutomationWebhook events via Inngest, HMAC verification
DeliveryExternal API integration (BulkSMS)
DeploymentBackend + frontend deployment, URL configuration

Every SeloraX app follows this same pattern. The specifics of what your app does in steps 5-6 will differ, but the platform integration points remain the same.