Headless status page.
Your UI, our data.
Don't like our status page? Build your own. Every byte the hosted version shows is available via a public REST API and a realtime SSE stream. Full OpenAPI spec.
Why headless
Every other status page vendor locks you into their template. We let you walk away with the data and keep using us.
Your brand, your pixels
Match your main site exactly. Custom fonts, animations, layouts. No vendor footer, no branded headers.
Render it anywhere
Next.js server component, Astro island, static HTML, Slack bot, CLI, in-app banner. Same endpoint.
Keep it on your domain
No CNAME required. Fetch from your server, render inside your app. Customers never see a third-party URL.
Integrate, don't migrate
Add a status widget to your docs, admin panel, or customer portal without redirecting users off-site.
One fetch. Everything you need.
GET the status endpoint with your slug. Parse the JSON. Render.
curl https://api.pulseapi.tech/status/acme{
"page": {
"id": "acme",
"title": "Acme API Status",
"language": "en",
"customDomain": "status.acme.com"
},
"overallStatus": "operational",
"endpoints": [
{
"id": "ep_1",
"name": "API",
"status": "operational",
"uptime24h": 99.98,
"avgResponseTime": 127,
"sparkline": [120, 118, 131, 127, 125],
"uptime90d": [100, 100, 99.9, 100, ...]
}
],
"components": [...],
"incidents": [...]
}Drop it into your stack
React
export default async function Status() {
const res = await fetch('https://api.pulseapi.tech/status/acme', {
next: { revalidate: 30 },
})
const data = await res.json()
return (
<section>
<h1>{data.page.title}</h1>
<StatusBanner status={data.overallStatus} />
{data.endpoints.map((ep) => (
<EndpointRow key={ep.id} endpoint={ep} />
))}
</section>
)
}Vue / Nuxt
<script setup lang="ts">
const { data } = await useFetch('https://api.pulseapi.tech/status/acme', {
key: 'status',
server: true,
})
</script>
<template>
<h1>{{ data.page.title }}</h1>
<p>Status: {{ data.overallStatus }}</p>
<ul>
<li v-for="ep in data.endpoints" :key="ep.id">
{{ ep.name }} — {{ ep.status }} ({{ ep.uptime24h }}%)
</li>
</ul>
</template>Vanilla JS
async function renderStatus() {
const res = await fetch('https://api.pulseapi.tech/status/acme')
const data = await res.json()
document.getElementById('status').innerHTML = `
<h2>${data.page.title}</h2>
<p>${data.overallStatus}</p>
`
}
renderStatus()
setInterval(renderStatus, 30_000)Realtime via SSE — no polling
Subscribe to incident updates, status transitions, and check results as they land.
const es = new EventSource('https://api.pulseapi.tech/sse/status/acme')
es.addEventListener('status:changed', (e) => {
const payload = JSON.parse(e.data)
updateBanner(payload.status)
})
es.addEventListener('incident:created', (e) => {
showNotification(JSON.parse(e.data))
})
es.addEventListener('check:completed', (e) => {
const check = JSON.parse(e.data)
appendToSparkline(check.endpointId, check.responseTime)
})Framework-specific guides
Pick your stack — we have a guide with copy-paste code.
FAQ
What is a headless status page?
A headless status page separates the data (uptime, components, incidents) from the UI. Instead of being locked into a vendor's template, you fetch the data from an API and render it however you want — your own React component, a server-rendered page, even a terminal dashboard.
Why not just use your hosted status page?
You can — it works out of the box. But if your brand needs a custom layout, tight integration with your main site, or rendering on your own domain without a CNAME, headless gives you complete freedom. Same data, any UI.
Is the API rate-limited?
The public status endpoint is designed for heavy read traffic (it is what powers our own hosted status pages and embedded badges). Reasonable polling is fine. For very high traffic, cache responses for 10-30 seconds or subscribe to our SSE stream for live updates.
Can I use this with a static site generator?
Yes. Fetch our status API at build time with Next.js getStaticProps, Astro frontmatter, or an equivalent. For live updates, either ISR/revalidate with short TTL, or switch that page to server-rendered.
What does the API return?
Status page metadata (title, branding), overall status, endpoints with per-endpoint status and uptime, components, active incidents, 90-day uptime arrays for uptime bars, and response-time sparkline data. Full spec at api.pulseapi.tech/docs.
Do I need authentication?
For the public status endpoint — no. It is the same URL your customers would see on the hosted version. For dashboard APIs (creating endpoints, writing incidents) you need an API key.
Can I subscribe to real-time updates instead of polling?
Yes. Connect to the SSE endpoint at /sse/status/:slug and receive status changes, new incidents, and check results as they happen.
How do I handle authentication for private status pages?
Generate an org API key in the dashboard and send it as an Authorization header when you fetch the status endpoint from your server. Never expose the key to the browser.
Ship a status page on your terms
Free tier, no credit card. Hosted, headless, or both.