HMAC-signed webhooks for every iMessage lifecycle event. Build real-time workflows, sync your CRM, and react to replies instantly.
Cover every stage of the iMessage lifecycle.
Fires when an iMessage is successfully sent (accepted by Tuco)
Fires when sending fails after all retries — technical error, reason included
Fires when the recipient has no iMessage — route the text to your SMS provider
Fires when the recipient replies — reply text and conversation history included
Fires when the recipient reacts (tapback) to a message you sent
Fires on iMessage read receipts (when enabled by the recipient) or email opens
Fires when the AI copilot drafts a reply for review — approve or reject via the API
Fires when a draft is approved and sent, from any channel — dashboard, Telegram, or API
Fires when a draft is rejected from any channel
Every webhook includes an x-tuco-signature header. Verify it to ensure authenticity.
const crypto = require('crypto');
function verifyWebhook(payload, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
// In your webhook handler:
app.post('/webhook', (req, res) => {
const signature = req.headers['x-tuco-signature'];
const isValid = verifyWebhook(
JSON.stringify(req.body),
signature,
process.env.TUCO_WEBHOOK_SECRET
);
if (!isValid) return res.status(401).send('Invalid signature');
// Process the event
const { event, data } = req.body;
console.log(`Received ${event}`, data);
res.status(200).send('OK');
});Every event follows a consistent JSON structure.
{
"event": "message.reply",
"timestamp": "2026-04-15T10:30:00Z",
"data": {
"message_id": "msg_abc123",
"from": "+15550100200",
"to": "+15550123456",
"body": "Sure, I'm interested. When can we talk?",
"line_id": "line_xyz789",
"campaign_id": "camp_def456"
}
}Set up your webhook endpoint and start receiving events in minutes.