Webhooks
Configure Viafoura webhooks to receive near real-time audience engagement events, including follow and unfollow events.
Viafoura can send audience engagement events to your own systems in near real time. Business intelligence and reporting dashboards can be enriched and empower your staff with insights into the real-time activity of your audience as they engage with content and each other.
Webhook types
Viafoura offers three webhooks. Each one sends its own set of events to its own URL, so you can turn on only the ones you need.
| Webhook | What it sends | Sent to |
|---|---|---|
| Content Action Webhook | Activity on comments, replies, chat messages, live blog posts, reviews, and Live Q&A, such as posts, likes, flags, pins, and moderation | Content data webhook URL |
| User Action Webhook | Activity by or about a user: following or unfollowing authors and topics, poll and quiz votes, and bans | User action webhook URL |
| Notification Webhook | Notifications addressed to specific users, and broadcasts | Notification webhook URL |
Content Action Webhook
Capture actions taken on community content, such as posting, liking, flagging, or pinning comments. Ideal for analyzing content engagement, monitoring moderation activity, and integrating content data into external systems.
User Action Webhook
Track user-level activities, such as following or unfollowing users and topics, voting in polls and quizzes, and account bans. Useful for synchronizing user activity with external systems and automating workflows based on user relationships or restrictions.
Notification Webhook
Extend Viafoura's notifications and broadcasts to your own communication channels. Designed for delivering notifications through email, push notifications, or newsletters using existing tools and preferences. The Notification Webhook has its own events and request format, described on the Notifications Webhook page.
The Content Action and User Action webhooks use the same request format, described on this page. Use message_type to tell their events apart.
Each webhook sends only to its own URL. If the User action webhook URL is empty, follow, poll vote, and ban events are not sent, even when the Content data webhook URL is set.
Setup
You will need to:
- Configure an HTTPS endpoint for each webhook you want to receive. Because the Content Action and User Action webhooks use the same request format, one endpoint can receive both: provide the same URL for each.
- Provide us with an authorization value we can pass to your API to let you know it's coming from us. It must be at least 64 bytes, hexadecimal.
Please contact your client success representative with this information and they will get this set up with you.
These are the settings involved, in Viafoura Admin → General → Notifications. Some appear under an older label, shown in parentheses.
| Setting | Applies to |
|---|---|
| Enable webhooks (Server-to-server callback) | All three webhooks. Turns webhook delivery on or off for the site. |
| Webhook authorization header (server-to-server callback authorization header) | All three webhooks. Sent in the authorization header of every request. |
| Content data webhook URL (content server-to-server callback url) | Content Action Webhook |
| User action webhook URL | User Action Webhook |
| Notification webhook URL (Notification server-to-server callback URL) | Notification Webhook |
Request format
This section applies to both the Content Action and User Action webhooks.
Security
Note that:
The service will be available over SSL (https) using a valid certificate
Viafoura application will use the certificate for both Authentication and Authorization
Conversation Pattern
The conversation between client and server will be Fire and Forget.
RESTful Service Specification
Request
Scheme: https
URL: will be provided by you to your CS representative
*HTTP Method: POST
Parameters
Request Headers
| Header name | Description |
|---|---|
| x-request-id | Random request ID provided by viafoura on each HTTP request, the value is the same as “request_uuid” in the request body |
| authorization | At least 64 bytes, hexadecimal. Please provide this to your CS representative |
| content-type | application/json; charset=utf-8 |
| accept | application/json |
Request Body
The request body is a JSON encoded string that follows the schema below:
| Field | Type | Description |
|---|---|---|
| request_uuid | string | Same as “X-Request-ID” in header |
| time | number | The time in milliseconds |
| version | number | The current value is 1 |
| events | array | Array of Event object |
Event object
Event objects describe state changes in the Viafoura system. Additional fields may be included based on message_type and action.
| Field | Type | Description |
|---|---|---|
| event_uuid | string | Event ID |
| time | number | The time in milliseconds |
| user_agent | string | HTTP User-Agent header captured when the event was generated; may be absent for internally-generated events (e.g. moderation actions). |
| message_type | string | The type of item or activity. See Content Action events and User Action events for every value and the webhook that sends it. |
| action | string | What happened to the item. See the event tables below for the actions each message_type supports. |
| detail | object | Event-specific details for poll_vote and user_ban events. Absent for other event types. |
| content_uuid | string | ID of the content item that was interacted with. For poll_vote, this is the poll UUID and equals detail.poll_uuid. |
| actor_uuid | string | id of the user or actor who caused the interaction (this could be internal ids in the case of moderation events) |
| author_uuid | string | id of the user who created the content (e.g. the author of the comment) |
| topic_id | string | Topic identifier for follow_topic events. Absent for other event types. |
| topic_name | string | Optional human-readable topic name for follow_topic events. Absent for other event types. |
| content_container_uuid | string | id of the content container that was interacted on |
| section_uuid | string | id of the viafoura section where the action occurred |
| page_url | string | Full URL where the action occurred. Absent for poll_vote events. |
Response
HTTP Status
A 200, 201 or 202 response code is expected in the HTTP response code. However third-party service can return other status codes to let our customer success team help with diagnosing possible issues in the integration.
| Error Code | Description |
|---|---|
| 404 | Not Found |
| 500 | Any internal error |
| 400 | Data is not valid |
| 200-201 | Request accepted |
| 403 | Authorization failed |
Response Body from Third Party Service
The expected response from the third party service will only be parsed if the following schema is used.
| Field | Type | Description |
|---|---|---|
| request_uuid | string | request_id of corresponding request |
| results | array | Array of Result objects |
Result object
| Field | Type | Description |
|---|---|---|
| event_uuid | string | Event ID |
| type | string | Either “success” or “failure” |
| error_type | string | Arbitrary value |
| error_description | string | Arbitrary value |
Example response
{
"request_uuid": "c71b5cb1-ce44-4239-8b6e-87b99cf2b1f0",
"results": [
{
"event_uuid":"c71b5cb1-ce44-4239-8b6e-87b99cf2b1a0",
"type": "failure",
"error_type": "unknown",
"error_description": "unable to store"
},
{
"event_uuid":"dd519c8a-3619-4cb0-b31b-0ffd14d24aab",
"type": "success"
},
{
"event_uuid":"d8a6a231-0cef-4385-83d8-66b6160811a5",
"type": "success"
},
{
"event_uuid":"5c0c5ab3-f3be-4194-bfc5-2000f94665ad",
"type": "success"
}
]
}Content Action events
Sent to the Content data webhook URL.
| Message Type | Action | Trigger |
|---|---|---|
| livecomment_post | created | new comment created |
| livecomment_post | visible | comment enabled after moderation |
| livecomment_post | disabled | comment disabled by moderation or if the report (flag) threshold has been reached |
| livecomment_post | updated | comment modified |
| livecomment_post | liked | comment liked by a user |
| livecomment_post | unliked | comment like reverted by a user |
| livecomment_post | disliked | comment disliked by a user |
| livecomment_post | undisliked | comment dislike reverted by a user |
| livecomment_post | flagged | comment has been reported |
| livecomment_post | spammed | comment was marked as spam by moderation |
| livecomment_post | pinned | comment was pinned to the top |
| livecomment_post | unpinned | comment was unpinned from the top |
| livecomment_post | picked | comment was marked as "editor's pick" |
| livecomment_post | unpicked | removed the "editor's pick" mark from the comment |
| reply_to_livecomment_post | created | new comment reply created |
| reply_to_livecomment_post | visible | comment reply enabled after moderation |
| chat_message | created | chat message is created |
| chat_message | visible | chat message is enabled after moderation |
| chat_message | liked | chat message liked by a user |
| chat_message | unliked | chat message like reverted by a user |
| chat_message | disliked | chat message disliked by a user |
| chat_message | undisliked | chat message dislike reverted by a user |
| reply_to_chat_message | created | chat message reply is created |
| reply_to_chat_message | visible | chat message reply is enabled after moderation |
| liveblog_post | created | liveblog post is created |
| liveblog_post | disabled | liveblog post disabled by admin |
| liveblog_post | updated | liveblog post modified |
| liveblog_post | liked | liveblog post liked by a user |
| liveblog_post | unliked | liveblog post like reverted by a user |
| liveblog_post | disliked | liveblog post disliked by a user |
| liveblog_post | undisliked | liveblog post dislike reverted by a user |
| liveblog_post | picked | liveblog post was marked as "editor's pick" |
| liveblog_post | unpicked | removed the "editor's pick" mark from the liveblog post |
| liveblog_post | pinned | liveblog post was pinned to the top |
| liveblog_post | unpinned | liveblog post was unpinned from the top |
| livereview_post | created | new review was created |
| livereview_post | visible | review enabled after moderation |
| livereview_post | disabled | review disabled due to moderation |
| livereview_post | updated | review edited/changed |
| livereview_post | liked | review marked as helpful by a user |
| livereview_post | unliked | review marked as not helpful by a user |
| livereview_post | disliked | review unmarked as helpful by a user |
| livereview_post | undisliked | review unmarked as not helpful by a user |
| livereview_post | flagged | review has been reported |
| livereview_post | spammed | review marked as spam |
| livereview_post | pinned | review pinned to the top |
| livereview_post | unpinned | review unpinned from top |
| livereview_post | picked | review marked as "editors pick" |
| livereview_post | unpicked | removed the "editor's pick" mark from the review |
| reply_to_livereview_post | created | a reply to a review was created |
| reply_to_livereview_post | visible | review reply enabled after moderation |
| livequestion | created | new Live Q&A session created |
| livequestion | updated | Live Q&A session details modified (title, settings) |
| livequestion | started | Live Q&A session moved from Upcoming to Live |
| livequestion | concluded | Live Q&A session moved from Live to Concluded |
| livequestion | reopened | Live Q&A session moved from Concluded back to Live |
| livequestion_post | created | new question created |
| livequestion_post | visible | question enabled after moderation |
| livequestion_post | disabled | question disabled by moderation or if the report (flag) threshold has been reached |
| livequestion_post | updated | question modified |
| livequestion_post | deleted | question deleted |
| livequestion_post | liked | question liked by a user |
| livequestion_post | unliked | question like reverted by a user |
| livequestion_post | disliked | question disliked by a user |
| livequestion_post | undisliked | question dislike reverted by a user |
| livequestion_post | flagged | question has been reported |
| livequestion_post | spammed | question was marked as spam by moderation |
| reply_to_livequestion_post | created | new question reply created |
| reply_to_livequestion_post | visible | question reply enabled after moderation |
Example request
{
request_uuid: 'abcc2254-b0a4-492c-a8f2-ae7820f4968a',
time: 1593205167183,
version: 1,
events:
[
{ event_uuid: '99d2a532-e1a1-4455-834a-775148570e9d',
time: 1593205166938,
section_uuid: '00000000-0000-4000-8000-337a437adec1',
content_container_uuid: '0dc371b9-cecd-4dc3-954b-e5255794e2e7',
content_uuid: 'bf890170-4828-4d1d-a1b0-a0072a6117d3',
actor_uuid: '00000000-0000-4000-8000-017ea245f200',
author_uuid: '00000000-0000-4000-8000-485fe358a524',
message_type: 'livecomment_post',
page_url: 'https://action.click/livecomments/actioncomments.html',
action: 'liked'
}
]
}User Action events
Sent to the User action webhook URL. These events use the same request format as Content Action events.
| Message Type | Action | Trigger |
|---|---|---|
| follow_author | followed | a user follows another user (author) |
| follow_author | unfollowed | a user unfollows another user (author) |
| follow_topic | followed | a user follows a topic |
| follow_topic | unfollowed | a user unfollows a topic |
| poll_vote | voted | a signed-in user votes in a poll or quiz |
| user_ban | banned | A user is banned |
| user_ban | unbanned | A user is unbanned |
Follow events
For follow events,
content_uuid,content_container_uuid, andpage_urlare absent.actor_uuidis the user performing the follow. Forfollow_author,author_uuidis the user being followed.
Follow author request
{
request_uuid: 'abcc2254-b0a4-492c-a8f2-ae7820f4968a',
time: 1593205167183,
version: 1,
events: [
{
event_uuid,
time,
section_uuid,
actor_uuid,
author_uuid,
message_type: 'follow_author',
action: 'followed'
}
]
}Follow topic request
{
request_uuid: 'abcc2254-b0a4-492c-a8f2-ae7820f4968a',
time: 1593205167183,
version: 1,
events: [
{
event_uuid,
time,
section_uuid,
actor_uuid,
message_type: 'follow_topic',
action: 'followed',
topic_id: 'sports/nba',
topic_name: 'NBA'
}
]
}The unfollowed variants are identical except action: 'unfollowed'.
Poll vote event fields
For poll_vote events, detail contains a snapshot of the poll when the vote was cast. Later changes to the question or options do not change an event that has already been delivered. Quizzes send the same poll_vote event with detail.is_quiz set to true.
| Field | Type | Description |
|---|---|---|
detail.poll_uuid | string | Poll UUID. This intentionally duplicates content_uuid so the detail object is self-contained. |
detail.poll_question | string | Poll question at the time of the vote. Absent if the upstream record does not contain a question. |
detail.is_quiz | boolean | Whether the poll is configured as a quiz. |
detail.options | array of PollVoteOption | Every poll option in presentation order, including options the voter did not select. The array can be empty when the upstream record contains no options. |
detail.options[].option_uuid | string | Option UUID. |
detail.options[].option_description | string | Option description at the time of the vote. |
detail.options[].is_selected | boolean | Whether the voter selected this option. At most one option is true; all options are false when the selection cannot be resolved upstream. |
detail.options[].is_correct | boolean | Whether this option is a correct quiz answer. |
For poll_vote events, actor_uuid identifies the voter. author_uuid, topic_id, topic_name, and page_url are absent. Fields with null values are omitted from the request body.
When poll votes are not delivered
Viafoura does not send a poll_vote event when:
- A signed-out visitor casts the vote. Poll-vote events require
actor_uuid. - The upstream record has no payload or poll UUID.
- The source topic message is not a vote.
Poll vote request
{
"request_uuid": "3f578154-5e7b-470e-8f40-038f5c40d08c",
"time": 1788381240669,
"version": 1,
"events": [
{
"event_uuid": "01a063d4-1d55-714c-8bdf-36f732b99465",
"section_uuid": "00000000-0000-4000-8000-000000000bda",
"content_container_uuid": "01a063d0-37d6-7b71-bf52-af42d0c01016",
"content_uuid": "9f1c2f7e-0000-4000-8000-000000000001",
"actor_uuid": "00000000-0000-4000-8000-0000000013b1",
"message_type": "poll_vote",
"action": "voted",
"detail": {
"poll_uuid": "9f1c2f7e-0000-4000-8000-000000000001",
"poll_question": "Which option do you prefer?",
"is_quiz": true,
"options": [
{
"option_uuid": "aaaa0000-0000-4000-8000-000000000001",
"option_description": "Option A",
"is_selected": true,
"is_correct": true
},
{
"option_uuid": "bbbb0000-0000-4000-8000-000000000002",
"option_description": "Option B",
"is_selected": false,
"is_correct": false
}
]
}
}
]
}User ban event fields
Receive user ban and unban notifications through events with message_type set to user_ban. Use action to distinguish between banned and unbanned events.
Both actions include ban information and user identifiers in detail. The affected user’s UUID appears in detail.author_uuid, rather than a top-level author_uuid field.
| Field | Type | Description |
|---|---|---|
detail.author_uuid | string | UUID of the user who is banned or unbanned. |
detail.ban_uuid | string | UUID identifying the ban. |
detail.ban_type | string | Type of ban. The examples below show full. |
detail.started_at | number | Ban start timestamp in milliseconds. |
detail.ends_at | number | Ban end timestamp in milliseconds. |
detail.is_permanent | boolean | Whether the ban is permanent. |
detail.message_to_user | string | Ban message addressed to the user. |
detail.user | object | Information identifying the affected user. |
detail.user.email | string | User’s email address. |
detail.user.name | string | User’s name. |
detail.user.viafoura_id | object | User’s Viafoura identifiers. |
detail.user.viafoura_id.uuid | string | User’s Viafoura UUID. |
detail.user.viafoura_id.id | number | User’s numeric Viafoura ID. |
detail.user.external_id | object | User’s external identity provider and identifier. |
detail.user.external_id.provider | string | Identity provider, such as vf_email_login. |
detail.user.external_id.id | string | User’s identifier within that provider. |
Banned user request
This example shows a non-permanent full ban.
{
"request_uuid": "3546bca5-22a9-4b45-807f-3b3ccd47dfb5",
"time": 1792085996681,
"version": 1,
"events": [
{
"event_uuid": "2ebc566e-048f-424d-aa58-291f613ddd74",
"time": 1792085996535,
"section_uuid": "00000000-0000-4000-8000-01fb38b8132b",
"message_type": "user_ban",
"action": "banned",
"detail": {
"author_uuid": "00000000-0000-4000-8000-03373e1ad915",
"ban_uuid": "00000000-0000-4000-8000-03a9dd78b46d",
"ban_type": "full",
"started_at": 1792085996000,
"ends_at": 1792089596000,
"is_permanent": false,
"message_to_user": "Message to the user. You are full banned",
"user": {
"email": "[email protected]",
"name": "Banned user",
"viafoura_id": {
"uuid": "00000000-0000-4000-8000-03373e1ad915",
"id": 3535800031509
},
"external_id": {
"provider": "vf_email_login",
"id": "00000000-0000-4000-8000-03373e1ad915"
}
}
}
}
]
}Unbanned user request
This example shows the same ban after the user is unbanned. The ban_uuid remains the same, while ends_at reflects the updated ban end timestamp.
{
"request_uuid": "68a12492-f8e1-40c9-b9a6-c60a2eaa7ed7",
"time": 1792086027455,
"version": 1,
"events": [
{
"event_uuid": "043e426a-6a95-4cb4-922b-e42c8a55f548",
"time": 1792086027401,
"section_uuid": "00000000-0000-4000-8000-01fb38b8132b",
"message_type": "user_ban",
"action": "unbanned",
"detail": {
"author_uuid": "00000000-0000-4000-8000-03373e1ad915",
"ban_uuid": "00000000-0000-4000-8000-03a9dd78b46d",
"ban_type": "full",
"started_at": 1792085996000,
"ends_at": 1792086027401,
"is_permanent": false,
"message_to_user": "Message to the user. You are full banned",
"user": {
"email": "[email protected]",
"name": "Banned user",
"viafoura_id": {
"uuid": "00000000-0000-4000-8000-03373e1ad915",
"id": 3535800031509
},
"external_id": {
"provider": "vf_email_login",
"id": "00000000-0000-4000-8000-03373e1ad915"
}
}
}
}
]
}Integration Testing
- Sign up for RequestBin which is a free Webhook testing platform.
- Pipedream will provide a public callback URL. In Viafoura Admin → General → Notifications for the site you want to test, enter it as the Content data webhook URL, the User action webhook URL, or both, depending on which events you want to test (see below).
- You will also need to get your API key from your Pipedream account by going to your Pipedream Account Settings page.
- In the same settings, under Webhook authorization header (server-to-server callback authorization header), enter your Pipedream API key as
Bearer <your API key>(see below). - Contact your Viafoura Customer Success Manager to enable webhooks for your domain.

Done! Now when you perform actions that trigger webhook messages on the site you configured you will see the Webhook messages in Pipedream under the page for the Requestbin you created.
Updated 3 days ago
