Docs

API overview

The API lets your own tools read what PulseKeeper knows: incidents, monitors and uptime. A typical use is a report you build yourself, for example a monthly summary in your own template or a dashboard that combines several services.

The API is read-only for now and is part of the Solo plan and above.

Endpoints

Endpoint
GET /api/v1/incidents Confirmed incidents in a period, newest first
GET /api/v1/incidents/{id} One incident
GET /api/v1/monitors Every monitor of the team
GET /api/v1/monitors/{id} One monitor
GET /api/v1/monitors/{id}/uptime Availability of one monitor in a period

All of them live under http://pulsekeeper.io/api/v1.

Tokens

Create a token under Settings → API. Only owners and admins can create or revoke one.

  • A token belongs to the team, not to the person who created it. It keeps working when that person leaves.
  • The token is shown once. We only store a hash of it, so copy it straight away. If you lose it, revoke it and create a new one.
  • A team can have up to 10 tokens. Give each tool its own, so you can revoke one without breaking the others.

Authentication

Send the token in the Authorization header of every request, as Bearer followed by the token. Keep it on your server: anyone with the token can read your incidents.

cURL

curl http://pulsekeeper.io/api/v1/monitors \
  -H "Authorization: Bearer $PULSEKEEPER_TOKEN" \
  -H "Accept: application/json"

PHP

<?php

// composer require guzzlehttp/guzzle
$client = new GuzzleHttp\Client([
    'base_uri' => 'http://pulsekeeper.io/api/v1/',
    'headers' => [
        'Authorization' => 'Bearer '.getenv('PULSEKEEPER_TOKEN'),
        'Accept' => 'application/json',
    ],
]);

$monitors = json_decode($client->get('monitors')->getBody(), true)['data'];

JavaScript

const response = await fetch('http://pulsekeeper.io/api/v1/monitors', {
  headers: {
    Authorization: `Bearer ${process.env.PULSEKEEPER_TOKEN}`,
    Accept: 'application/json',
  },
});

const { data: monitors } = await response.json();

Go

req, _ := http.NewRequest("GET", "http://pulsekeeper.io/api/v1/monitors", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("PULSEKEEPER_TOKEN"))
req.Header.Set("Accept", "application/json")

res, err := http.DefaultClient.Do(req)
if err != nil {
	log.Fatal(err)
}
defer res.Body.Close()

Conventions

  • IDs are short strings, such as "3f9a1c0e7b2d4a58". Use them as they are; they never change.
  • Times are ISO 8601 in UTC, such as "2026-09-30T21:14:05Z". Convert them to your own time zone for the report.
  • Periods take from and to as a date or a date and time with an offset: 2026-09-01 or 2026-09-01T00:00:00+02:00. In a URL, write the + as %2B.
  • Unknown is null. A value we have not measured is null, never 0 or 100.
  • History goes back as far as your plan allows, the same as in the app. Asking for more returns 422 with an explanation instead of a shorter answer, so a report never looks better than the month was.

Errors

Errors are JSON with a message; validation errors also have errors per parameter.

{
  "message": "Your plan keeps 365 days of history.",
  "errors": { "from": ["Your plan keeps 365 days of history."] }
}
Status Meaning
401 The token is missing, wrong or revoked.
403 Your plan no longer includes the API, or the account is suspended. The token itself stays and works again after the plan changes.
404 No such incident or monitor in your team.
422 A parameter is invalid or the period goes back further than your plan allows.
429 Too many requests: wait for the number of seconds in the Retry-After header.

Rate limit

120 requests per minute per token. Every answer carries X-RateLimit-Limit and X-RateLimit-Remaining. A monthly report for 50 clients fits easily; if you poll, once a minute is plenty, because incidents are confirmed within about a minute anyway.