Badges, feeds & calendar
Live badges, lifecycle subscriptions, and scheduled maintenance in calendar clients
Public surfaces
On this page8
The public, unauthenticated embed surface of a status page. No API key anywhere on this page: everything here is public information by design, same as the status page itself. The dashboard's Status page → Embeds & feeds page generates feed and calendar URLs with copy buttons, alongside the named badge and widget editors. The public badge routes below remain compatible for existing installations.
All examples use the permanent page address acme.inbrief.sh. A live custom domain
can also serve the legacy public routes, but copied machine integrations should keep the
permanent address so a later custom-domain change does not strand them.
Named badges and the status widget
Each badge or widget you create under Status page → Embeds & feeds is an
installation with a public id: emb_ followed by 21 lowercase letters and digits. The editor
gives you snippets to paste. The addresses below are always on your page's permanent address, and each
one answers only for an installation that belongs to that page.
| URL | What it is |
|---|---|
/embed/v1/widget.js | The loader script. Give it
data-installation="emb_…" and it draws that widget where the tag sits. If the widget is
switched off for your page, the script is empty and does nothing. |
/embed/v1/installations/{id}/frame | The widget as a page of its own, for an
<iframe>. |
/embed/v1/installations/{id}/badge.svg | The installation's badge as an SVG image, for a README or anywhere scripts cannot run. |
/embed/v1/installations/{id}/config.json | The installation's settings as JSON. The loader reads it; the editor calls it the widget JSON URL. |
The loader snippet is one async script tag whose src is
https://acme.inbrief.sh/embed/v1/widget.js, with data-installation set to the
installation's id and referrerpolicy="no-referrer". Copy it from the editor rather than
typing it.
A badge never breaks: an unknown, removed or switched-off installation draws a grey
unknown badge instead. The frame and config.json answer 404 in that
case, config.json with the body {"available":false}, and those answers are never
cached.
Successful answers are cached publicly for up to five minutes, and for less when a service is about to go
stale. Each carries a strong ETag; send it back as If-None-Match and an
unchanged answer is 304 with no body. If-Modified-Since is not used. The
script and both JSON documents can be fetched from any website.
Page status as JSON
https://acme.inbrief.sh/embed/v1/pages/pg_…/status.json?lang=arThe current state of the page and each public service in one small document, for code that draws its own
indicator. It is what the widget itself reads. The address contains your page's public key,
pg_ followed by 21 lowercase letters and digits. Copy the address from
Status page → Embeds & feeds, under Status JSON. ?lang= picks one
of the languages your page publishes.
{
"schemaVersion": 1,
"language": "en",
"page": {
"slug": "acme",
"name": "Acme",
"url": "https://status.example.com/",
"overall": "degraded",
"lastCheckedAt": "2026-10-15T09:41:00.000Z"
},
"services": [
{
"slug": "checkout-api",
"name": "Checkout API",
"measurement": "degraded",
"freshness": "live",
"maintenance": "none",
"overall": "degraded",
"lastCheckedAt": "2026-10-15T09:41:00.000Z"
}
],
"activeIncidents": [
{
"id": "inc_01",
"title": "Slow checkout",
"summary": "Payments are taking longer than usual. We are looking into it.",
"impact": "degraded",
"phase": "investigating",
"serviceSlugs": [
"checkout-api"
],
"startedAt": "2026-10-15T09:30:00.000Z",
"updatedAt": "2026-10-15T09:35:00.000Z",
"url": "https://status.example.com/incidents/inc_01"
}
],
"activeMaintenances": []
}overall is one of operational, degraded, outage,
maintenance, stale, paused or unknown. An active
incident's impact wins over everything else, then active maintenance, then a paused or stale monitor, then
the latest check. A key that does not belong to the page on that address answers 404. Caching,
ETags and cross-origin access work as for the other addresses in this section.
Legacy badge routes
These shields.io-style SVG routes remain available for compatibility with existing embeds. A shared
cache keeps a badge for at most 30 seconds, and for less when the monitor behind it is about to
go stale. Every response carries a strong ETag; send it back as
If-None-Match and an unchanged badge answers 304 with no body. The dashboard
does not configure these routes; it configures named badges instead. See the
badges and widgets guide.
| URL | What it shows |
|---|---|
/badge.svg | The whole page: operational, degraded
(some monitors down), down, or unknown. |
/badge/{service}.svg | One monitor, labelled with its name:
operational, down, or unknown. |
{service} is the monitor's slug, visible in the dashboard's monitor list, or
programmatically in GET /api/public/{slug}/summary (each entry's
slug field).
Styles
?style=uptime replaces the status word with a 30-day uptime figure, e.g.
99.97%. The window is fixed at 30 days regardless of the history window your page
displays. That is the badge convention, and the two are different measurements.
[](https://acme.inbrief.sh/)Language
?lang= draws the badge in one of the languages your page publishes, so a badge
embedded on an Arabic marketing site reads in Arabic even when your page's default is English.
Without it the badge uses your page's default language. A language your page does not publish
falls back to that default rather than failing, the same way an unrecognised style does.
[](https://acme.inbrief.sh/)JSON variant
/badge.json and /badge/{service}.json return the same data in the
shields.io endpoint-badge schema, so shields.io can render it in any of its own styles:
{
"schemaVersion": 1,
"label": "Checkout API",
"message": "operational",
"color": "#2F7A55"
}Never a dead end
A badge URL never 404s. An unrecognised service slug (renamed, deleted, or a typo) and even an
unrecognised hostname render the grey unknown badge, because a broken image icon in
someone else's README reads as the service itself being broken, so the badge always draws.
Feeds
/feed.xml (RSS 2.0) and /feed.atom (Atom) serialise the same latest
100 public lifecycle events. That includes incident opening, meaningful updates and resolution;
maintenance announcement, updates, overrun, completion and cancellation; and postmortem publication.
Both addresses use the same two optional query filters:
| Filter | Effect |
|---|---|
?lang={code} | The feed in any language the page publishes
(en, ar, fr, es). An unpublished code
falls back to the default language. |
?service={slug} | Only events that touched that monitor. An unknown slug yields valid empty feeds, never a 404, because a renamed monitor must not hard-break a standing subscription. |
Filters combine with &:
https://acme.inbrief.sh/feed.xml?service=api&lang=arhttps://acme.inbrief.sh/feed.atom?service=api&lang=arBoth feeds are cached for five minutes.
A page created before lifecycle feeds existed serves the older feed instead: /feed.xml
carries its incident ledger, the latest 100 incidents, and /feed.atom answers
404.
Maintenance calendar
/maintenance.ics is an iCalendar subscription containing up to 150 scheduled/open
one-off windows and the 50 most recent completed or cancelled windows. Add it once to a calendar
client and later schedule changes move the same event instead of creating duplicates.
| Filter | Effect |
|---|---|
?lang={code} | Localised event title and summary in a language the page publishes. An unpublished code falls back to the page default. |
https://acme.inbrief.sh/maintenance.ics?lang=arTimes are absolute UTC instants and calendar apps display them in each reader's timezone.
Rescheduling preserves the event UID and advances its sequence and timestamp. Recent cancelled
work remains in the bounded feed with STATUS:CANCELLED. The calendar is cached for
five minutes.