Plan with AI

Get started →
Use CasesSearch & Content Discovery IntegrationsWorkvivo Content in External Search & AI Tools
Search & Content Discovery IntegrationsArticles APIPages APIDocuments APIWebhooks

Workvivo Content in External Search & AI Tools

Overview

Build an intermediary layer that uses Workvivo APIs and webhooks to index and sync content with third-party search platforms and AI assistants, so employees can access Workvivo knowledge from whatever tool they already use.

Workvivo holds a wealth of organisational knowledge (articles, pages, documents, updates, event details) but employees don't always start their search in Workvivo. They might use an enterprise search platform (Elasticsearch, Coveo, Glean), an AI assistant (ChatGPT, Copilot, custom RAG systems), or a knowledge management tool that aggregates content from multiple sources. If Workvivo content isn't indexed in those systems, it becomes invisible to employees who rely on them.

This use case combines the Workvivo API (for initial content extraction and backfill) with webhooks (for ongoing change notifications) to build a sync layer for external search platforms and AI tools. The API provides access to articles, pages, and document-library records for the initial index build, while webhooks notify the integration about supported create, update, and delete events.

Value & Benefits

Make Workvivo content discoverable everywhere. Employees find Workvivo articles, pages, and documents from whatever search tool or AI assistant they already use - without needing to switch to Workvivo to search.

Reduce stale search results. Webhooks notify the integration about supported content changes, allowing the external index to be updated without waiting for the next full sync.

Power AI assistants with organisational knowledge. Feed Workvivo content into RAG (Retrieval-Augmented Generation) pipelines so AI assistants can answer employee questions using your actual company knowledge, policies, and announcements.

Support a unified enterprise search strategy. Organisations using platforms like Coveo, Glean, or Elasticsearch can include Workvivo as a content source alongside email, documents, and other systems - delivering truly unified search.

Maintain content integrity on deletion. Webhook deletion events allow you to immediately remove content from external indexes when it's deleted or archived in Workvivo, preventing employees from finding outdated or retracted information.

Applications

Enterprise search indexing. Feed Workvivo articles, pages, and documents into your enterprise search platform (Elasticsearch, Coveo, Glean, Algolia) so employees find internal communications and knowledge base content from their primary search tool.

AI assistant knowledge base. Index Workvivo content into a vector database (Pinecone, Weaviate, Qdrant) to power a RAG pipeline, enabling AI assistants to answer employee questions using actual company policies, announcements, and documentation.

Intranet aggregation. Sync Workvivo content to a central knowledge hub or digital workplace platform that aggregates content from multiple internal systems into a single searchable interface.

Chatbot knowledge enrichment. Feed Workvivo articles and pages into your existing chatbot's knowledge base so it can answer employee questions with up-to-date company information sourced directly from Workvivo.

Content analytics and reporting. Stream all content events to an analytics platform to track publishing velocity, content freshness, authorship patterns, and engagement across the organisation.

Content export for supported types. Maintain a separate copy of the articles, pages, and document metadata needed by an approved search, analytics, or knowledge workflow.

Technical Details

Before running the initial backfill, complete Quick Start to create an app and API key and find your Base URL and Workvivo-Id.

Architecture

The sync layer operates in two phases:

  1. Initial backfill - Use the API to extract existing content (articles, global pages, pages in accessible spaces, and document-library items) and build the initial index.
  2. Real-time sync - Subscribe to webhooks for ongoing create, update, and delete events to keep the index current.

Phase 1: Initial Backfill via API

curl -X GET "https://api.workvivo.com/v1/articles?skip=0&take=50" \
  -H "Authorization: Bearer $WORKVIVO_TOKEN" \
  -H "Workvivo-Id: $WORKVIVO_ORG_ID" \
  -H "Accept: application/json"
curl -X GET "https://api.workvivo.com/v1/pages?skip=0&take=50" \
  -H "Authorization: Bearer $WORKVIVO_TOKEN" \
  -H "Workvivo-Id: $WORKVIVO_ORG_ID" \
  -H "Accept: application/json"
curl -X GET "https://api.workvivo.com/v1/documents?skip=0&take=50" \
  -H "Authorization: Bearer $WORKVIVO_TOKEN" \
  -H "Workvivo-Id: $WORKVIVO_ORG_ID" \
  -H "Accept: application/json"

All collection endpoints support pagination via skip and take parameters. Iterate through all pages until no more results are returned.

GET /v1/pages returns global pages by default. To index pages that belong to a space, repeat the request with space_id={space_id} for each accessible space you want to include. The document endpoints return document-library metadata and file or external-link URLs; extract file text in your search or RAG pipeline if you need full-text document indexing.

Phase 2: Real-Time Sync via Webhooks

See Webhooks Fundamentals for endpoint registration, request verification, retries, idempotency, and out-of-order delivery. This use case focuses on the events and processing specific to this workflow.

Subscribe to content lifecycle events in Admin > Platform > Webhook Settings. The user configuring webhooks must have the Developer role in Workvivo to access this page. Click Create Webhook to add a new endpoint.

When configuring a search-sync webhook, select:

  • Webhook Name: A name that helps identify the search-sync webhook later.
  • Webhook URL: The HTTPS endpoint that will receive POST requests.
  • Authentication: No Authentication or OAuth 2.0. OAuth 2.0 adds Login URL, Client ID, Client Secret, and optional custom form parameters for the token request.
  • Custom Headers: Optional headers to include with each webhook request
  • Subscribed Events: The article, page, and document event checkboxes your external index needs. New event types are not automatically subscribed to existing webhooks.
  • Content Scope: Send webhooks for only public content, or send webhooks for all content when the index is allowed to include private and hidden content.

Webhook Payload Examples

{
    "action": "article.published",
    "article": {
        "id": 93,
        "external_id": 93,
        "slug": "welcome-aboard",
        "title": "Welcome Aboard - Here's all you need to know!",
        "html_content": "<p>Key Contacts</p><p>The key point of contact for your onboarding is the HR Team...</p>",
        "creator": {
            "id": 240,
            "name": "James Ashton",
            "email": "ja@example.com",
            "job_title": "Marketing Executive"
        },
        "published_at": "2026-06-17T09:00:00Z",
        "created_at": "2026-06-17T08:30:00Z",
        "updated_at": "2026-06-17T09:00:00Z",
        "permalink": "https://yourcompany.workvivo.com/articles/welcome-aboard"
    },
    "meta": {
        "id": "4m32k5ykq5",
        "attempt": 1,
        "timestamp": 1750154400
    }
}
{
    "action": "article.deleted",
    "article": {
        "id": 93,
        "title": "Welcome Aboard - Here's all you need to know!",
        "permalink": "https://yourcompany.workvivo.com/articles/welcome-aboard"
    },
    "meta": {
        "id": "9k42m8xyz1",
        "attempt": 1,
        "timestamp": 1750167000
    }
}

Webhook Delivery Behaviour

  • Timeouts: Workvivo has a 5-second connection timeout and a 5-second response timeout. Your endpoint must connect and respond within these windows.
  • Retries: If your endpoint does not return a 2xx response, Workvivo retries up to 4 additional times (5 total attempts) with exponential delay between retries.
  • Ordering: Events may arrive out of order. For payloads that include updated_at, use it to resolve conflicts (latest timestamp wins).
  • Idempotency: Use the meta.id field to deduplicate retried deliveries - the same id is used across all retry attempts for a given event.
  • OAuth authentication: If OAuth 2.0 is configured, Workvivo retrieves an access token from your Login URL and sends it as an Authorization: Bearer ... header in addition to the standard webhook headers.

JavaScript Integration Examples

Treat the initial backfill and real-time webhook processing as separate workflows. Both call the same customer-owned search-index functions.

Initial Backfill

Paginate through each Workvivo collection and add the existing content to your index. Global pages and pages in individual spaces are loaded separately.

import { indexDocument } from './search-index.js';

const apiUrl = 'https://api.workvivo.com/v1';
const headers = {
    Authorization: `Bearer ${process.env.WORKVIVO_TOKEN}`,
    'Workvivo-Id': process.env.WORKVIVO_ORG_ID,
    Accept: 'application/json',
};

async function* fetchAll(path, filters = {}) {
    const take = 50;
    let skip = 0;

    while (true) {
        const query = new URLSearchParams({ ...filters, skip, take });
        const response = await fetch(`${apiUrl}${path}?${query}`, { headers });

        if (!response.ok) {
            throw new Error(`Workvivo API request failed: ${response.status}`);
        }

        const result = await response.json();

        for (const item of result.data ?? []) {
            yield item;
        }

        if (!result.meta?.pagination?.next_page) {
            return;
        }

        skip += take;
    }
}

export async function runBackfill(spaceIds) {
    for await (const article of fetchAll('/articles')) {
        await indexDocument('article', article.id, {
            title: article.title,
            body: article.html_content,
            url: article.permalink,
        });
    }

    for await (const page of fetchAll('/pages')) {
        await indexDocument('page', page.id, {
            title: page.title,
            body: page.html_content,
            url: page.permalink,
        });
    }

    for (const spaceId of spaceIds) {
        for await (const page of fetchAll('/pages', { space_id: spaceId })) {
            await indexDocument('page', page.id, {
                title: page.title,
                body: page.html_content,
                url: page.permalink,
            });
        }
    }

    for await (const document of fetchAll('/documents')) {
        await indexDocument('document', document.id, {
            title: document.label,
            description: document.description,
            url: document.document?.url,
        });
    }
}
export async function indexDocument(contentType, id, content) {
    // Add or update this item through your search platform's SDK or API.
}

export async function removeDocument(contentType, id) {
    // Remove this item through your search platform's SDK or API.
}

Real-Time Updates

Use a separate webhook receiver to keep the index current after the backfill.

import express from 'express';
import { indexDocument, removeDocument } from './search-index.js';

const app = express();
app.use(express.json());

app.post('/webhooks/search-sync', async (request, response) => {
    const payload = request.body;
    const [contentType, event] = payload.action.split('.');
    const resource = payload[contentType];

    if (!resource) {
        return response.status(200).json({ status: 'ignored' });
    }

    if (['deleted', 'archived', 'expired'].includes(event)) {
        await removeDocument(contentType, resource.id);
    } else if (['created', 'updated', 'published'].includes(event)) {
        await indexDocument(contentType, resource.id, resource);
    }

    return response.status(200).json({ status: 'processed' });
});

app.listen(3000);