Receiving inbound & webhooks.
When a customer replies to your number, the paired phone reports it instantly. Mobile API Connect can auto-reply, email you, or POST a signed JSON webhook to your own endpoint.
How inbound works
๐ฑ Customertexts your number
โ
๐ฒ Your phoneapp captures SMS
โ
โ๏ธ Mobile API Connectrules engine
โ
๐ Your endpointsigned webhook
Three ways to receive
| Method | Set where | Fires when |
|---|---|---|
| Auto-reply rules | Portal โ Rules | A rule matches (can also email / webhook). Guide โ |
| Forward-all webhook | PUT /v1/webhooks | Every inbound message, regardless of rules |
| Per-integration | Ingress outboundUrl | Each ERP connection can mirror inbound to its own URL |
Configure a webhook
Point the forward-all webhook at your endpoint:
curl -X PUT https://api.mobileapiconnect.com/v1/webhooks \ -H "Authorization: Bearer sk_live_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://yourapp.com/hooks/sms-inbound","enabled":true}'
Prefer no code? Set the same thing in the portal under Webhooks, or on the phone's dashboard under Connect your ERP โ Forward URL.
Inbound payload
Your endpoint receives an HTTP POST with this JSON body:
{
"event": "message.received",
"from": "919876543210",
"to": "911234500000",
"text": "balance",
"ref": null,
"receivedAt": "2026-06-12T14:32:00.000Z",
"deviceId": "dev_โฆ",
"tenantId": "ten_โฆ",
"tenantName": "Acme Corp",
"matchedRuleId": "rule_โฆ"
}| Field | Meaning |
|---|---|
| event | Always message.received for inbound |
| from | The customer's number |
| to | Your gateway number that received it |
| text | The exact message body |
| matchedRuleId | Present only if a rule matched (omitted on forward-all) |
Verify the signature
If you set a signing secret, every request carries an HMAC signature so you can confirm it's really us. The header is X-MAC-Signature and the value is sha256=<hex>, where the HMAC-SHA256 is computed over the raw request body using your whsec_ secret.
Verify before you JSON-parse. Compute the HMAC over the exact raw bytes you received โ re-serializing the parsed object can change whitespace and break the match.
import crypto from "node:crypto"; // rawBody = exact bytes received; header = req.header("X-MAC-Signature") function verify(rawBody, header, secret) { const provided = header.includes("=") ? header.split("=").pop() : header; const expected = crypto.createHmac("sha256", secret).update(rawBody).digest("hex"); const a = Buffer.from(expected), b = Buffer.from(provided); return a.length === b.length && crypto.timingSafeEqual(a, b); } // Express: capture raw body, then verify app.post("/hooks/sms-inbound", express.raw({ type: "*/*" }), (req, res) => { const raw = req.body.toString("utf8"); if (!verify(raw, req.header("X-MAC-Signature"), process.env.MAC_WEBHOOK_SECRET)) return res.status(401).end(); const msg = JSON.parse(raw); // โฆ handle msg.from / msg.text โฆ res.sendStatus(200); });
Responding
- Return a
2xxquickly (under ~8s). Anything else is logged as a failed delivery. - Do slow work asynchronously โ acknowledge first, process after.
- Be idempotent: the same message could arrive more than once on a retry.