PulseWise API Documentation

Welcome to the PulseWise API documentation. This RESTful API provides access to healthcare data and analytics.

Base URL

https://pulsewise.com

Version

v1

Response Format

JSON

Getting Started

Quick Start Guide

  1. Register for an API account and obtain your API key
  2. Include your API key in the Authorization header of all requests
  3. Make your first API call to test connectivity
  4. Explore the available endpoints below

Test Your Connection

curl -H "Authorization: Bearer YOUR_API_KEY" \
     https://pulsewise.com/api/v1/status

Authentication

PulseWise API uses Bearer token authentication. Include your API key in the Authorization header:

Authorization: Bearer YOUR_API_KEY

API Endpoints

Log Monitor ingest

Your application posts an hourly summary of what happened; PulseWise tells you when those numbers stop looking like your application. Everything below is what you need to write a client — see Log Monitor to create a source and get its key.

Send every hour, including empty ones

Post each hour even when every count is zero. A zero is a measurement; a missing hour is the absence of one. If quiet hours are skipped, "nobody used the site" becomes indistinguishable from "the site stopped reporting" — and a source that stops reporting is treated as down. Skipping empty hours will get you paged for an outage you do not have.

POST https://pulsewise.com/api/v1/logs/ingest
Authenticate with X-Ingest-Key: ls_…. This is the source's own key, not a pk_ API key — it can only write that one source's counts, and revoking it does not affect your API access.

Request

{
  "hours": [
    {
      "hour": "2026-09-08T14:00:00Z",     // start of the hour, ISO 8601, UTC
      "events": {                          // omit a type, or send 0 — same thing
        "login_success": 42,
        "login_failure": 3,
        "password_reset": 1
      },
      "distinct_users": 31,                // optional
      "distinct_ips": 28,                  // optional
      "new_ips": 4                         // optional
    }
  ]
}

Batching

Up to 48 hours per request. Send one hour at a time normally; send several to catch up after downtime.

Safe to retry

Re-posting an hour replaces it rather than adding to it, so a timeout you are unsure about can simply be retried. A duplicate would otherwise look exactly like a spike.

Accepted window

Backfill up to 7 days. Hours more than 90 minutes ahead of our clock are refused — check the clock on the sending server.

Event types

Send whichever apply. Unknown names are ignored rather than rejected, so a client reporting something newer than this server does not lose the hours that came with it.

Key Meaning Assessed
login_success Successful logins Per hour, against that hour of the week
login_failure Failed logins Per hour, against that hour of the week
page_view Page views Per hour, against that hour of the week
password_reset Password resets Over a rolling window
user_created Users created Over a rolling window
user_deleted Users deleted Over a rolling window
role_changed Roles changed Over a rolling window
plugin_activated Plugins activated Over a rolling window
plugin_deactivated Plugins deactivated Over a rolling window
theme_changed Themes changed Over a rolling window
core_updated Core updated Over a rolling window
post_published Posts published Per hour, against that hour of the week
file_changed Files changed Over a rolling window
admin_login Administrator logins Over a rolling window

Response

HTTP 202
{
  "success": true,
  "accepted": 1,
  "rejected": [],                          // anything refused is named, never silently dropped
  "next_expected_hour": "2026-09-08T15:00:00+00:00"
}

202 with a non-empty rejected array means some hours were not stored and why. Log it — a client that ignores it will keep resending the same rejected hours forever while its operator believes the site is monitored. 401 is an unknown or rotated key, 403 a paused source, 422 a malformed body.

A worked example

curl -X POST https://pulsewise.com/api/v1/logs/ingest   -H "X-Ingest-Key: ls_your_key_here"   -H "Content-Type: application/json"   -d '{"hours":[{"hour":"2026-09-08T14:00:00Z","events":{"login_success":42,"login_failure":3},"distinct_users":31}]}'

In a Laravel application, an hourly scheduled command is usually the whole client:

// Runs hourly. Reports the hour that has just closed — including
// the hours when nothing happened, which is the point.
$hour = now()->utc()->subHour()->startOfHour();

Http::withHeaders(['X-Ingest-Key' => config('services.pulsewise.ingest_key')])
    ->post('https://pulsewise.com/api/v1/logs/ingest', [
        'hours' => [[
            'hour' => $hour->toIso8601String(),
            'events' => [
                'login_success'  => Activity::type('login')->inHour($hour)->count(),
                'login_failure'  => Activity::type('login_failed')->inHour($hour)->count(),
                'password_reset' => Activity::type('password_reset')->inHour($hour)->count(),
            ],
            'distinct_users' => Activity::inHour($hour)->distinct('user_id')->count(),
        ]],
    ])->throw();

Send counts, not records

The endpoint accepts numbers and nothing else. No usernames, email addresses, IP addresses or log lines are wanted or stored — which keeps your users' data on your server, keeps this well clear of GDPR obligations, and means a breach here would reveal how busy you were and nothing more.

Site Monitor — scheduled malware scanning

The /api/malware/{target} endpoint above is a one-shot check: it fetches a page and tells you whether known malware is being served right now. With no history to compare against, it cannot tell you that something changed.

Site Monitor is the stateful half. Register a website and PulseWise fetches its home page — and any same-domain sub-pages you name — on a cadence you choose, then reports what it finds.

ALERT

Known malware is being served. A payload signature matched, packed JavaScript was found inlined in the page, or a script appeared from a host that is on a threat feed or that the site has never used before.

REVIEW

Something changed since the baseline you accepted. On a live site this is usually a plugin or theme update. Kept separate from alerts on purpose — blurring the two is what makes a scanner unreadable.

The baseline only moves when you move it

Changes are reported every scan until you accept the current state of the site. Nothing is adopted automatically, because a baseline that updates itself would absorb a slow injection one scan at a time.

Email only when there is something new

A report is sent only when a scan finds something the previous scan did not, so a change you have seen and chosen to leave unaccepted does not mail you every hour. A scan that finds nothing is silent.

Error Codes

Code Status Description
200OKRequest successful
400Bad RequestInvalid request parameters
401UnauthorizedInvalid or missing API key
403ForbiddenAccess denied
404Not FoundResource not found
429Too Many RequestsRate limit exceeded
500Internal Server ErrorServer error

Rate Limits

The PulseWise API implements rate limiting to ensure fair usage and maintain service quality.

Rate Limit

1000 requests per hour

Rate Limit Headers

X-RateLimit-Limit
X-RateLimit-Remaining
X-RateLimit-Reset

Support

Need help with the PulseWise API? Here are some resources:

Email: support@pulsewise.com
Documentation: Latest version