Skip to content

Search is only available in production builds. Try building and previewing the site to test it out locally.

Webhooks

Webhooks allow your application to receive real-time notifications when events occur in your Mando account.

Instead of polling the API, configure webhook endpoints to receive HTTP POST requests when:

  • Sales are completed
  • Products are updated
  • Stock levels change
  • Customers are created or modified
  1. Log in to your Mando admin panel
  2. Navigate to SettingsWebhooks
  3. Click Add Webhook
  4. Enter your endpoint URL
  5. Select the events you want to receive
  6. Save the configuration
EventDescription
sale.createdNew sale completed
sale.voidedSale was voided
product.createdNew product added
product.updatedProduct details changed
product.deletedProduct removed
stock.updatedStock level changed
stock.lowStock fell below threshold
customer.createdNew customer added
customer.updatedCustomer details changed
businessday.openedBusiness day started
businessday.closedBusiness day ended

All webhooks use a consistent payload structure:

{
"id": "evt_abc123",
"type": "sale.created",
"created": "2024-01-15T10:30:00Z",
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"total": 45.50,
"items": [...]
}
}
FieldDescription
idUnique event identifier
typeEvent type
createdISO 8601 timestamp
dataEvent-specific payload

Each webhook request includes a signature header for verification:

X-Mando-Signature: sha256=abc123...

Verify the signature to ensure the request came from Mando:

import crypto from 'crypto';
function verifyWebhook(
payload: string,
signature: string,
secret: string
): boolean {
const expected = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature.replace('sha256=', '')),
Buffer.from(expected)
);
}
// Express middleware
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.headers['x-mando-signature'] as string;
const isValid = verifyWebhook(req.body, signature, process.env.WEBHOOK_SECRET!);
if (!isValid) {
return res.status(401).send('Invalid signature');
}
const event = JSON.parse(req.body);
// Process event...
res.status(200).send('OK');
});
import hmac
import hashlib
def verify_webhook(payload: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(
secret.encode(),
payload,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(
signature.replace('sha256=', ''),
expected
)
# Flask example
@app.route('/webhook', methods=['POST'])
def handle_webhook():
signature = request.headers.get('X-Mando-Signature')
is_valid = verify_webhook(
request.data,
signature,
os.environ['WEBHOOK_SECRET']
)
if not is_valid:
return 'Invalid signature', 401
event = request.json
# Process event...
return 'OK', 200

Process events based on their type:

app.post('/webhook', (req, res) => {
const event = req.body;
switch (event.type) {
case 'sale.created':
handleNewSale(event.data);
break;
case 'stock.low':
sendRestockAlert(event.data);
break;
case 'customer.created':
syncToMailingList(event.data);
break;
}
res.status(200).send('OK');
});

If your endpoint returns an error (non-2xx status), Mando retries the webhook:

AttemptDelay
1Immediate
21 minute
35 minutes
430 minutes
52 hours

After 5 failed attempts, the webhook is marked as failed and disabled.

  1. Respond quickly - Return 200 within 5 seconds; process asynchronously
  2. Handle duplicates - Use event.id for idempotency
  3. Verify signatures - Always validate incoming webhooks
  4. Use HTTPS - Webhook URLs must use HTTPS
  5. Log everything - Keep records for debugging
  6. Set up monitoring - Alert on failed webhook deliveries

Use the webhook test feature in the admin panel:

  1. Go to SettingsWebhooks
  2. Click Test next to your endpoint
  3. Select an event type
  4. Review the test payload delivery

For local development, use tools like ngrok to expose your local server.