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
      "changes": [                         // optional — see Notable changes
        {"event": "plugin_installed", "subject": "wordfence", "count": 1}
      ]
    }
  ]
}

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 In the hour's total traffic
login_failure Failed logins Per hour, against that hour of the week
page_view Page views In the hour's total traffic
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 Every occurrence (Notable changes)
plugin_deactivated Plugins deactivated Every occurrence (Notable changes)
theme_changed Themes changed Every occurrence (Notable changes)
core_updated Core updated Every occurrence (Notable changes)
post_published Posts published In the hour's total traffic
file_changed Files changed Over a rolling window
admin_login Administrator logins Over a rolling window
plugin_installed Plugins installed Every occurrence (Notable changes)
plugin_updated Plugins updated Every occurrence (Notable changes)
plugin_deleted Plugins deleted Every occurrence (Notable changes)
theme_installed Themes installed Every occurrence (Notable changes)
theme_updated Themes updated Every occurrence (Notable changes)
theme_deleted Themes deleted Every occurrence (Notable changes)
admin_granted Administrator rights granted Every occurrence (Notable changes)
option_changed Critical settings changed Every occurrence (Notable changes)
file_edited Files edited from the dashboard Every occurrence (Notable changes)
app_password_created Application passwords created Every occurrence (Notable changes)
page_published Pages published Over a rolling window
post_updated Published posts edited Over a rolling window
page_updated Published pages edited Over a rolling window
post_trashed Posts trashed Over a rolling window
page_trashed Pages trashed Over a rolling window
post_deleted Posts deleted Over a rolling window
page_deleted Pages deleted Over a rolling window
user_updated User profiles updated Over a rolling window
password_changed Passwords changed Over a rolling window
not_found Page-not-found (404) responses Per hour, against that hour of the week
comment_posted Comments posted Over a rolling window
comment_spam Comments marked as spam Per hour, against that hour of the week

Types added after the first release (404s, comments, content edits and the change events) count as measured only when you send them — send 0 for a quiet hour rather than leaving the key out, or PulseWise cannot tell "none happened" from "not counted".

Notable changes

Some things are worth hearing about every time, however normal their rate: a plugin installed at 3am, a new administrator. List them in the hour's changes array and each is reported once as its own finding. subject names what changed — a plugin or theme slug, a setting's name, a file path, a version — and must never name who: no usernames, emails or post titles. Also count each one in events under the same name. Up to 200 entries per hour; unknown events are ignored.

Event Reported as Severity
admin_granted A user was given administrator rights ALERT
option_changed Critical site setting changed ALERT
file_edited A file was saved from the dashboard editor ALERT
app_password_created An application password was created ALERT
plugin_installed Plugin installed REVIEW
plugin_updated Plugin updated REVIEW
plugin_deleted Plugin deleted REVIEW
plugin_activated Plugin activated REVIEW
plugin_deactivated Plugin deactivated REVIEW
theme_installed Theme installed REVIEW
theme_updated Theme updated REVIEW
theme_deleted Theme deleted REVIEW
theme_changed Active theme switched REVIEW
core_updated WordPress updated REVIEW

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