Article Publishing & Lifecycle Management
Overview
Organisations produce content across dozens of systems — corporate comms platforms, CMS tools, HR portals, marketing automation suites. Without integration, internal communicators are stuck manually copying and reformatting content into their employee experience platform.
The Workvivo Articles API eliminates this friction entirely. It lets you push articles directly into Workvivo from any system that can make an HTTP request, with full control over targeting, scheduling, and archival.
Whether you're syndicating leadership updates from your corporate CMS, auto-publishing compliance notices from a policy management system, or surfacing product release notes from your engineering wiki, the Articles API turns Workvivo into the single pane of glass for employee-facing content — without manual intervention.
Value & Benefits
Eliminate manual content duplication. Content authored in external systems flows directly into Workvivo. No copy-paste, no reformatting, no missed updates.
Ensure timely, consistent communication. Scheduled publishing means the right content reaches employees at the right time — across time zones, audiences, and business units — without someone pressing "publish" manually.
Maintain content hygiene at scale. Automated archival prevents stale content from cluttering the employee feed. Governance teams can enforce retention policies programmatically rather than relying on manual audits.
Reduce operational overhead for comms teams. Internal communications teams spend less time on logistics and more time on strategy. A single article authored in your CMS can be targeted to specific spaces, teams, or the entire organisation — automatically.
Support multilingual workforces natively. Language variant endpoints allow you to push translated content alongside the primary article, ensuring non-English-speaking employees receive communications in their preferred language without separate publishing workflows.
Applications
Corporate CMS syndication. Connect your existing content management system (e.g. Contentful, WordPress, Drupal) to Workvivo. When an article is published in your CMS, a webhook triggers creation in Workvivo — targeted to the appropriate audience. Updates in the CMS propagate automatically; archival in the CMS triggers a DELETE in Workvivo, which archives the article and removes it from active article listings.
Compliance & policy distribution. Push regulatory updates, policy changes, and mandatory notices from your GRC platform directly into Workvivo. Pair with audience targeting to ensure only affected teams or regions receive specific notices, and use published_at to align publication with policy effective dates.
Product & engineering release notes. Pipe release notes from tools like Notion, Confluence, or GitHub into Workvivo automatically — keeping the entire organisation informed about product changes without additional authoring burden on engineering teams.
HR & people operations announcements. Syndicate onboarding guides, benefits enrolment reminders, and organisational changes authored in your HRIS to Workvivo. Target by team or space to ensure relevance.
Executive communications. Feature leadership blogs and CEO updates prominently using the is_featured flag, ensuring high visibility without manual intervention from the comms team.
Scheduled content campaigns. Pre-author internal campaigns (e.g. Wellness Week, Sustainability Month) and schedule them for future publication using published_at timestamps — enabling "set and forget" content calendars.
Technical Details
Before using these examples, complete Quick Start to create an app and API key and find your Base URL and Workvivo-Id.
Create & Publish an Article
A single POST request creates and publishes an article. Setting published_at to a past or current timestamp publishes immediately; a future timestamp schedules it.
Required fields: title, html_content, published_at, and one of user_id / user_external_id / user_alias to identify the author displayed on the post. Boolean fields such as notify_users and is_featured are shown as 1/0 in these form-data examples. The optional external_id must be an integer — use a numeric ID from your source system rather than an arbitrary string slug. Setting is_featured=1 requires a primary image upload; the request will otherwise be rejected with Featured articles must have an image.
Omit the audience payload only when you intend the article to publish to the entire organisation (global audience). Include audience[type] plus audience[spaces][] or audience[teams][] to target specific spaces or teams.
cURL note: always use
--form-stringforhtml_content(and any other field whose value can begin with<). The-Fflag treats a leading<as a "read from file" directive and will fail withexit code 26on HTML input.
curl -X POST https://api.workvivo.com/v1/articles \
-H "Authorization: Bearer $WORKVIVO_TOKEN" \
-H "Workvivo-Id: $WORKVIVO_ORG_ID" \
-H "Accept: application/json" \
-F "user_id=240" \
-F "title=Q3 Benefits Enrollment Now Open" \
-F "subtitle=Action required by September 30" \
--form-string "html_content=<h2>Open Enrollment</h2><p>Benefits enrollment for Q3 is now open.</p>" \
-F "published_at=2026-06-15T09:00:00Z" \
-F "audience[type]=spaces" \
-F "audience[spaces][0]=12345" \
-F "audience[spaces][1]=67890" \
-F "notify_users=1" \
-F "external_id=7891"
{
"data": {
"id": 44201,
"external_id": 7891,
"slug": "q3-benefits-enrollment-now-open",
"title": "Q3 Benefits Enrollment Now Open",
"subtitle": "Action required by September 30",
"language_code": "en",
"html_content": "<h2>Open Enrollment</h2><p>Benefits enrollment for Q3 is now open.</p>",
"global_audience": false,
"is_featured": false,
"has_acknowledgement": false,
"published_at": "2026-06-15T09:00:00Z",
"created_at": "2026-06-11T13:00:00Z",
"updated_at": "2026-06-11T13:00:00Z",
"permalink": "https://yourcompany.workvivo.com/news/44201?source=api_permalink"
},
"status": "success",
"meta": {
"default_api_translation_language": "en"
}
}
Update an Existing Article
Use PUT with either the Workvivo article ID or your integer external ID to update content, retarget audiences, or change scheduling. PUT replaces the article — you must re-send the full required set (title, html_content, published_at, and one of user_id / user_external_id / user_alias) on every call, along with any fields you want to change.
curl -X PUT https://api.workvivo.com/v1/articles/44201 \
-H "Authorization: Bearer $WORKVIVO_TOKEN" \
-H "Workvivo-Id: $WORKVIVO_ORG_ID" \
-H "Accept: application/json" \
-F "user_id=240" \
-F "title=Q3 Benefits Enrollment Now Open" \
-F "subtitle=Action required by October 15" \
--form-string "html_content=<h2>Open Enrollment - Extended!</h2><p>Deadline extended to October 15.</p>" \
-F "published_at=2026-06-15T09:00:00Z"
curl -X PUT https://api.workvivo.com/v1/articles/by-external-id/7891 \
-H "Authorization: Bearer $WORKVIVO_TOKEN" \
-H "Workvivo-Id: $WORKVIVO_ORG_ID" \
-H "Accept: application/json" \
-F "user_id=240" \
-F "title=Q3 Benefits Enrollment Now Open" \
-F "subtitle=Action required by October 15" \
--form-string "html_content=<h2>Open Enrollment - Extended!</h2><p>Deadline extended to October 15.</p>" \
-F "published_at=2026-06-15T09:00:00Z"
{
"data": {
"id": 44201,
"external_id": 7891,
"title": "Q3 Benefits Enrollment Now Open",
"published_at": "2026-06-15T09:00:00Z",
"permalink": "https://yourcompany.workvivo.com/news/q3-benefits-enrollment-now-open"
},
"status": "success",
"meta": {}
}
Archive an Article
When content reaches end-of-life, archive it programmatically by Workvivo ID or by your source system's integer external ID. The DELETE endpoint currently archives the article and preserves associated assets/references; it does not permanently purge article data.
To schedule, reschedule, or remove an archival date, provide archive_at when creating an article with POST /v1/articles or updating it with PUT /v1/articles/{id}. Articles are automatically archived on that date and time. To archive an article immediately, call DELETE by Workvivo ID or external ID.
curl -X DELETE https://api.workvivo.com/v1/articles/44201 \
-H "Authorization: Bearer $WORKVIVO_TOKEN" \
-H "Workvivo-Id: $WORKVIVO_ORG_ID" \
-H "Accept: application/json"
curl -X DELETE https://api.workvivo.com/v1/articles/by-external-id/7891 \
-H "Authorization: Bearer $WORKVIVO_TOKEN" \
-H "Workvivo-Id: $WORKVIVO_ORG_ID" \
-H "Accept: application/json"
{
"data": {
"id": 44201,
"external_id": null
},
"status": "success",
"meta": {}
}
Add a Language Variant
For multilingual organisations, attach translated versions to an existing article. language_code, title, and html_content are required. Variants can also be updated (PUT /v1/articles/{id}/language-variant/{language_code}) and deleted (DELETE /v1/articles/{id}/language-variant/{language_code}), and both variants of each endpoint accept by-external-id/{external_id} in place of {id}.
curl -X POST https://api.workvivo.com/v1/articles/44201/language-variant \
-H "Authorization: Bearer $WORKVIVO_TOKEN" \
-H "Workvivo-Id: $WORKVIVO_ORG_ID" \
-H "Accept: application/json" \
-F "language_code=fr" \
-F "title=Inscription aux avantages Q3 maintenant ouverte" \
-F "subtitle=Action requise avant le 30 septembre" \
--form-string "html_content=<h2>Inscription ouverte</h2><p>L'inscription aux avantages pour le Q3 est maintenant ouverte.</p>"
{
"data": {
"id": 44201,
"title": "Q3 Benefits Enrollment Now Open",
"language_variants": [
{
"language_code": "fr",
"title": "Inscription aux avantages Q3 maintenant ouverte"
}
]
},
"status": "success",
"meta": {}
}
JavaScript Integration Example
Sync a CMS article to Workvivo by using the CMS record ID as the article's integer external_id. The same function creates, updates, or archives the Workvivo article.
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',
};
export async function syncArticle(cmsArticle) {
const externalId = Number(cmsArticle.id);
if (cmsArticle.status === 'archived') {
const response = await fetch(
`${apiUrl}/articles/by-external-id/${externalId}`,
{ method: 'DELETE', headers },
);
if (!response.ok) {
throw new Error(`Article archival failed: ${response.status}`);
}
return;
}
const form = new FormData();
form.set('user_external_id', cmsArticle.author_employee_id);
form.set('title', cmsArticle.title);
form.set('subtitle', cmsArticle.subtitle ?? '');
form.set('html_content', cmsArticle.body_html);
form.set('published_at', cmsArticle.published_at);
form.set('notify_users', cmsArticle.notify_users ? '1' : '0');
if (cmsArticle.space_ids.length > 0) {
form.set('audience[type]', 'spaces');
cmsArticle.space_ids.forEach((spaceId, index) => {
form.set(`audience[spaces][${index}]`, spaceId);
});
}
let response = await fetch(
`${apiUrl}/articles/by-external-id/${externalId}`,
{ method: 'PUT', headers, body: form },
);
if (response.status === 400) {
form.set('external_id', externalId);
response = await fetch(`${apiUrl}/articles`, {
method: 'POST',
headers,
body: form,
});
if (!response.ok) {
throw new Error(`Article creation failed: ${response.status}`);
}
} else if (!response.ok) {
throw new Error(`Article update failed: ${response.status}`);
}
}