n8n Triggers
The Tenreply Trigger node registers a webhook with Tenreply and fires your workflow every time the selected event occurs. One event per trigger node; add more trigger nodes to react to different events.
If your n8n instance cannot receive inbound HTTP, use Tenreply Trigger (Polling) instead — see the end of this page.
Events
| Group | Event | Fires when |
|---|---|---|
| Messaging | message.received | A customer sends a message (WhatsApp, Instagram DM, Messenger) |
message.sent | An agent or automation sends a message | |
message.delivered | A sent message is delivered | |
message.read | The customer reads a message | |
message.failed | Delivery fails | |
| Conversations | conversation.created | A new conversation starts |
conversation.status_changed | Opened, closed, pending, or a custom status label changes | |
conversation.assigned | Assigned to a team member or returned to the queue | |
| Contacts | contact.created | A contact is created — manually, by API, or from a first inbound message |
contact.updated | A contact record changes | |
contact.tagged | Tags are added to or removed from a contact (including automatic behaviour tags) | |
| Campaigns | broadcast.completed | A broadcast send finishes |
sequence.enrolled | A contact is enrolled in a drip sequence | |
sequence.completed | A contact reaches the end of a sequence | |
| Social | social_post.published | A LinkedIn, Instagram, or Facebook post goes live |
social_post.failed | A post could not be published | |
comment.received | Someone comments on an Instagram or Facebook post | |
| CRM | deal.created | A deal is added to a pipeline |
deal.stage_changed | A deal moves to another stage | |
deal.status_changed | A deal is marked won, lost, or reopened |
Every delivery carries the event name in the X-Tenreply-Event header.
Event payloads
message.received
{ "message": { "id": "msg_abc123", "conversationId": "conv_xyz", "contactId": "contact_def", "direction": "inbound", "type": "text", "content": { "text": "Hello, I need help!" }, "status": "delivered", "waMessageId": "wamid.abc", "timestamp": "2026-06-01T10:00:00.000Z" }, "conversation": { "id": "conv_xyz", "status": "open", "channel": "whatsapp", "contactId": "contact_def" }, "contact": { "id": "contact_def", "name": "Jane Doe", "phoneNumber": "1234567890" }}message.sent and message.failed carry { "message": { … } }; message.delivered and message.read carry { "waMessageId", "status", "errorMessage" }.
conversation.created / conversation.status_changed / conversation.assigned
{ "conversation": { "id": "conv_xyz", "status": "closed", "statusLabelId": null, "channel": "whatsapp", "contactId": "contact_def", "assignedAgentId": "user_42", "contact": { "id": "contact_def", "name": "Jane Doe" } }, "previousStatus": "open", "previousStatusLabelId": null, "changedByUserId": "user_42"}conversation.assigned replaces the previousStatus* keys with previousAssignedAgentId and assignedAgentId.
contact.created / contact.updated / contact.tagged
{ "contact": { "id": "contact_def", "phoneNumber": "1234567890", "name": "Jane Doe", "email": "jane@example.com", "tags": ["vip", "customer"], "createdAt": "2026-06-01T10:00:00.000Z" }, "source": "manual", "changes": ["tags"], "addedTags": ["customer"], "removedTags": []}source is manual (UI/API) or inbound (first message) on contact.created; changes lists the fields touched on contact.updated; addedTags / removedTags appear on contact.tagged, with source: "behaviour" when the CRM applied them automatically.
broadcast.completed
{ "broadcastId": "bcast_123", "broadcastSendId": "send_456", "name": "June promo", "channel": "whatsapp", "sent": 842, "failed": 3, "completedAt": "2026-06-01T11:00:00.000Z"}social_post.published / social_post.failed
{ "post": { "id": "post_789", "platform": "instagram", "postType": "reel", "caption": "Launch day 🚀", "mediaUrls": ["https://…/launch.mp4"], "status": "published", "externalPostId": "17895695668004550" }, "platform": "instagram", "postType": "reel", "status": "published", "externalPostId": "17895695668004550"}social_post.failed carries status: "failed" and an errorMessage.
comment.received
{ "platform": "instagram", "comment": { "commentId": "17912345678901234", "parentCommentId": null, "mediaId": "17895695668004550", "socialPostId": "post_789", "fromId": "1784…", "fromUsername": "jane.doe", "text": "Is this available in blue?", "commentedAt": "2026-06-01T12:00:00.000Z" }, "post": { "id": "post_789", "platform": "instagram", "caption": "Launch day 🚀" }}Facebook comments use postId and fromName instead of mediaId and fromUsername. Feed comment.commentId into Social Comment → Reply or Reply Privately.
deal.created / deal.stage_changed / deal.status_changed
{ "deal": { "id": "deal_1", "title": "Website redesign", "pipelineId": "pipe_1", "stageId": "stage_3", "contactId": "contact_def", "value": "2500.00", "currency": "INR", "status": "won", "stage": { "id": "stage_3", "name": "Won" } }, "previousStatus": "open", "status": "won"}deal.stage_changed carries previousStageId and stageId instead of the status keys.
sequence.enrolled / sequence.completed
{ "enrollment": { "id": "enr_1", "contactId": "contact_def", "sequenceId": "seq_1", "status": "active", "currentStep": 0 }, "sequence": { "id": "seq_1", "name": "Onboarding" }, "contactId": "contact_def"}Signature verification
Each delivery includes the header X-Tenreply-Signature: sha256=<hmac-hex>. The node verifies this automatically (constant-time) using the secret returned when the subscription was created. To skip verification (e.g. local testing), open the node’s Options and disable Verify Signature.
Tenreply Trigger (Polling)
For n8n instances without a public URL. The node polls Tenreply on the workflow’s schedule for one of:
| Event | Source |
|---|---|
| New Contact | Contacts, newest first |
| New Conversation | Conversations, newest first |
| New Inbound Message | Customer messages, newest first |
The first run after activation records what already exists instead of replaying it; later runs emit only rows the node has not seen, oldest first. “Fetch Test Event” returns the most recent row. Webhooks remain the better choice whenever they are possible: they fire instantly and cover all 20 events above.