Announcements API
Overview
The Announcements API returns the latest active announcement for app display. It is designed for in-app cards, banners, or update modals and includes rich-content fields such as summary text, cover image, gallery images, and action links.
Both announcementsLatest and
announcementAck require a valid Bearer JWT in the
Authorization header. The JWT is obtained via the
login endpoint.
Announcement object fields are returned in
camelCase (for example
coverImageUrl, actionLinks). Keep your
model mapping aligned with this.
The API tracks the last acknowledged announcement
per user on the server, so the
seen flag is consistent across all of the user's
devices. Call announcementAck once the user has
dismissed or viewed the announcement.
Get Latest Announcement
Returns exactly one record: the most recent announcement where
is_active = 1, publishedAt <= now,
and expiresAt is either null or in the
future.
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
query |
string |
Required | Must be "announcementsLatest" |
Authorization header |
string |
Required |
Bearer JWT token obtained from the
login endpoint.
|
cURL Example
curl -X POST "https://api.virtualperformancetool.com/api" \
-H "Content-Type: application/json" \
-H "X-API-Version: 1.3.6" \
-H "Authorization: Bearer <jwt>" \
-d '{
"query": "announcementsLatest"
}'
Response (announcement exists)
{
"apiVersion": "1.3.6",
"success": true,
"announcement": {
"id": "12",
"title": "VPT 4.0 Released",
"summary": "A short summary for list/cards.",
"body": "### Full details\nSupports markdown or plain text.",
"bodyFormat": "markdown",
"contentLabel": "Read changelog",
"contentUrl": "https://www.virtualperformancetool.com/changelog",
"coverImageUrl": "https://api.virtualperformancetool.com/admin/assets/uploads/announcements/announcement_12_cover_20260415_111500_123456.jpg",
"galleryImages": [
{
"url": "https://api.virtualperformancetool.com/admin/assets/uploads/announcements/announcement_12_gallery_20260415_111530_654321.jpg",
"caption": "Cockpit view",
"altText": "A220 cockpit"
}
],
"actionLinks": [
{
"label": "Update now",
"url": "https://www.virtualperformancetool.com/download"
}
],
"publishedAt": "2026-04-10 09:00:00",
"expiresAt": "2026-05-10 09:00:00",
"seen": false
}
}
Response (no active announcement)
{
"apiVersion": "1.3.6",
"success": true,
"announcement": null
}
Response Fields
When available, announcement contains the fields below.
Nullable fields may be null or empty arrays depending
on editorial content.
| Field | Type | Description |
|---|---|---|
id |
string |
Announcement identifier. |
title |
string |
Main headline. |
summary |
string|null |
Short teaser text for compact layouts. |
body |
string|null |
Detailed content body. |
bodyFormat |
string |
Content format hint. Current values: markdown,
html, plain.
|
contentLabel |
string|null |
Primary CTA label shown as a button text. |
contentUrl |
string|null |
Primary CTA target URL. |
coverImageUrl |
string|null |
Main hero/cover image URL. |
galleryImages |
array |
Optional image list. Each item may include
url, caption, and
altText.
|
actionLinks |
array |
Optional list of secondary links. Each item has
label and url.
|
publishedAt |
string |
Publication timestamp in YYYY-MM-DD HH:MM:SS.
|
expiresAt |
string|null |
Optional expiration timestamp. null means no
auto-expiration.
|
seen |
boolean |
true if the authenticated user has already
acknowledged this announcement via
announcementAck. Use this to suppress the
announcement UI without any client-side storage.
|
Acknowledge Announcement
Marks an announcement as seen for the authenticated user. The
server stores the highest acknowledged
id — calling this with an older ID than already
stored has no effect, so it is safe to call redundantly.
This endpoint requires a valid Bearer JWT in the
Authorization header.
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
query |
string |
Required | Must be "announcementAck" |
data.id |
integer |
Required |
The id of the announcement the user has seen.
Use the value returned by
announcementsLatest.
|
Request Body
{
"query": "announcementAck",
"data": {
"id": 12
}
}
cURL Example
curl -X POST "https://api.virtualperformancetool.com/api" \
-H "Content-Type: application/json" \
-H "X-API-Version: 1.3.6" \
-H "Authorization: Bearer <jwt>" \
-d '{
"query": "announcementAck",
"data": { "id": 12 }
}'
Response
{
"apiVersion": "1.3.6",
"success": true
}
Integration Tips
When to fetch
Fetch at app startup and optionally after login. Avoid aggressive polling.
Rendering strategy
Use summary for list cards, body for the
detail modal/screen, and coverImageUrl as top media.
Render galleryImages only when non-empty.
Body format handling
Respect bodyFormat. For markdown/html rendering, always
sanitize before display. For plain text, preserve line breaks.
Detecting new announcements
Use the server-side seen flag — no local storage
needed. The flag reflects the user's state across all their devices.
// 1. Fetch (JWT required)
const response = await fetch('https://api.virtualperformancetool.com/api', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Version': '1.3.6',
'Authorization': `Bearer ${jwt}`
},
body: JSON.stringify({ query: 'announcementsLatest' })
});
const data = await response.json();
if (data.success && data.announcement && !data.announcement.seen) {
showAnnouncement(data.announcement);
}
// 2. When the user dismisses/views the announcement:
await fetch('https://api.virtualperformancetool.com/api', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Version': '1.3.6',
'Authorization': `Bearer ${jwt}`
},
body: JSON.stringify({
query: 'announcementAck',
data: { id: data.announcement.id } // pass the id exactly as returned
})
});