API-first

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
curl https://api.pulseapi.tech/status/acme
Response (excerpt)
{
  "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

app/status/page.tsx
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

pages/status.vue
<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

status.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.

live status updates
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.