Skip to main content

Webhooks and Delivery Notifications

There are two ways to track message delivery: polling and webhooks. Choose the approach that best fits your use case.

Polling

Query the delivery status on demand:

GET /messages/status/{customerMessageId}

Or check multiple messages at once:

GET /messages/status?customerMessageIds=id1,id2,id3

When to use polling:

  • Low message volume
  • Ad-hoc status checks
  • Simple integrations that don't need a public endpoint

Webhooks

Register an HTTPS callback URL to receive delivery status updates in real time, as soon as the carrier reports them.

Configure a webhook

POST /webhooks/delivery-status

Provide your callback URL. The API will send HTTP POST requests to this URL whenever a message status changes.

Manage your webhook

ActionEndpoint
Get current webhookGET /webhooks/delivery-status
Create webhookPOST /webhooks/delivery-status
Update webhook URLPUT /webhooks/delivery-status
Revoke webhookDELETE /webhooks/delivery-status
info

Only one active delivery-status webhook is allowed per account. Creating a new one replaces the previous configuration.

Webhook flow

Webhook payload

When a message status changes, the API sends a POST request to your callback URL.

Delivery notification example:

{
"eventType": "DELIVERY",
"messageId": "e76614d1-4ac1-4d94-89f0-d07f1b5a190c",
"customerMessageId": "order-12345",
"destination": "+393401234567",
"statusCode": 3,
"description": "Message delivered",
"channel": "SMS",
"timestamp": "2026-04-09T10:30:00Z"
}

Read notification example (WhatsApp/RCS only):

{
"eventType": "READ",
"messageId": "e76614d1-4ac1-4d94-89f0-d07f1b5a190c",
"destination": "+393401234567",
"channel": "WHATSAPP",
"timestamp": "2026-04-09T10:31:15Z"
}

Inbound message example:

{
"eventType": "INBOUND",
"source": "+393401234567",
"destination": "+393409876543",
"text": "Yes, I confirm my appointment",
"channel": "WHATSAPP",
"messageType": "TEXT",
"timestamp": "2026-04-09T10:32:00Z"
}
Status CodeMeaning
3Delivered
6Undeliverable
8Expired

Testing webhooks locally

To test webhooks during development, use ngrok to expose your local server:

# Start your local webhook handler on port 3000
node webhook-handler.js

# In another terminal, expose it via ngrok
ngrok http 3000

# Copy the HTTPS URL (e.g. https://abc123.ngrok.io)
# Register it as your webhook callback:
curl -X POST "https://lora-api.agiletelecom.com/api/partner-gateway/v1/webhooks/delivery-status" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"callbackUrl": "https://abc123.ngrok.io/webhook"}'
tip

Use simulation: true when sending test messages — the message won't be delivered but you'll still receive webhook callbacks.

Example webhook handler (Node.js)

webhook-handler.js
const express = require('express');
const app = express();
app.use(express.json());

app.post('/webhook', (req, res) => {
const { eventType, messageId, statusCode, channel } = req.body;

switch (eventType) {
case 'DELIVERY':
if (statusCode === 3) {
console.log(`Message ${messageId} delivered via ${channel}`);
// Update your database: mark message as delivered
} else if (statusCode === 6) {
console.log(`Message ${messageId} undeliverable via ${channel}`);
// Handle failure: retry or notify user
}
break;

case 'READ':
console.log(`Message ${messageId} read by recipient`);
break;

case 'INBOUND':
console.log(`Inbound from ${req.body.source}: ${req.body.text}`);
// Process reply: auto-respond, forward to CRM, etc.
break;
}

// Always respond quickly — process asynchronously if needed
res.sendStatus(200);
});

app.listen(3000, () => console.log('Webhook handler listening on port 3000'));

Best practices

  1. Use HTTPS -- Your callback URL must use HTTPS for security.
  2. Respond quickly -- Return a 200 OK response within a few seconds. Process the payload asynchronously if needed.
  3. Handle retries -- If your endpoint is unreachable, the system may retry delivery. Make your processing idempotent.
  4. Validate the source -- Verify that incoming webhooks originate from the Qlara Platform API.
  5. Monitor failures -- If your webhook endpoint is consistently failing, check your server logs and ensure the URL is accessible.

Choosing between polling and webhooks

AspectPollingWebhooks
LatencyDepends on poll frequencyNear real-time
ComplexitySimple GET requestsRequires a public HTTPS endpoint
ScalabilityIncreases API calls at scalePush-based, no extra API calls
Best forLow volume, ad-hoc checksHigh volume, real-time dashboards

See the Webhooks API Reference and Message Delivery Status API Reference for full endpoint documentation.