API Reference

Logging API: send logs, heartbeats and monitors to one endpoint

LogBlazer provides endpoints for ingesting logs, managing heartbeat monitors, and managing browser monitors. Send log data via POST and it appears in your dashboard. Register heartbeat URLs and LogBlazer will actively ping them on a schedule, tracking health checks, response times, and alerting you when things break. Register browser monitors and LogBlazer will load the page in a real browser and check what rendered against your own CSS selectors.

Last updated 2026-08-16

Base URL

https://app.logblazer.com

Log ingestion endpoint

POST/api/logs/{api_key}

The api_key is a UUID unique to each project. You can find it in your project settings on the LogBlazer dashboard. No other authentication is required — the key in the URL is your credential.

Request format

Headers

Content-Type: application/json

Body (JSON)

FieldTypeRequiredDescription
payloadstringYesThe log message content.
statusstringNoOne of: SUCCESS, FAILURE, WARNING, NOTICE. Defaults to NOTICE.
sourcestringNoIdentifies the origin of the log (e.g. web-server, cron-worker, deploy-script). Max 255 characters.
monitor_titlestringNo*Display name for the monitor on your project dashboard (e.g. CPU Usage, Deploy Status). Max 255 characters.
monitor_typestringNo*One of: status, boolean, number, text. Determines how the value is displayed on the dashboard.
monitor_valuestringNo*The current value for this monitor (e.g. healthy, true, 42). Max 255 characters.
monitor_statusstringNoControls the color tint of the monitor card. One of: success (green), failure (red), warning (yellow). Omit for a neutral appearance.
monitor_metastringNoFree-form secondary info shown next to the monitor's timestamp on the dashboard card (e.g. 3m 30sec, 42 ms, v2.4.1). Often a duration but free-form. Max 255 characters.

* Monitor fields are optional, but if any one is provided then all three (monitor_title, monitor_type, monitor_value) are required together.

Monitor cards

Monitors let you display the latest state of a value on your project dashboard. Each log entry can optionally include monitor data. The dashboard shows the most recent value for each unique monitor_title within a project.

Monitor types

TypeDescription
statusA status label such as healthy, degraded, or down.
booleanA true/false value (e.g. true or false).
numberA numeric value (e.g. 42, 99.8).
textFree-form text (e.g. v2.4.1, us-east-1).

Monitor status (color)

The optional monitor_status field controls the color tint of the monitor card on the dashboard. It is independent of the log status field.

ValueColorUse when
successGreenHealthy, deployed, passed, OK
failureRedFailed, error, down
warningYellowDegraded, slow, at capacity

When omitted, the monitor card renders with a neutral appearance.

Example: sending a monitor

curl -X POST https://app.logblazer.com/api/logs/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "payload": "Health check passed",
    "status": "SUCCESS",
    "source": "health-checker",
    "monitor_title": "API Status",
    "monitor_type": "status",
    "monitor_value": "healthy",
    "monitor_status": "success",
    "monitor_meta": "42 ms"
  }'

Monitor grouping and layout

Arrange monitors beneath a parent status card, collect older monitors under a named group, and choose side-by-side rows or stacked columns. In the project dashboard, select Arrange monitors to edit the layout, preview the Pipeline example in the editor, and save it. The same layout appears on the overview and public dashboards. The public /llm endpoint includes its JSON configuration.

Monitoring configs can manage the layout independently of log ingestion. Use the project's API key (not its public panel key). GET /api/monitor-layout/{apiKey} reads the configuration; PUT /api/monitor-layout/{apiKey} replaces it. Both return 200 with a monitor_layout field. An unknown key returns 404; invalid configuration returns 422 with validation errors and leaves the previous layout intact.

curl -X PUT "https://app.logblazer.com/api/monitor-layout/YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  --data-binary @monitor-layout.json

Save this request body as monitor-layout.json:

{
  "monitor_layout": {
    "direction": "column",
    "items": [
      {
        "monitor": "Pipeline",
        "direction": "row",
        "children": [
          { "monitor": "Beta" },
          { "monitor": "Dev" },
          { "monitor": "Staging" },
          { "monitor": "Staging E2E" }
        ]
      }
    ],
    "unlisted_group": "Old"
  }
}

This places Pipeline above Beta, Dev, Staging, and Staging E2E, in that order. Every other monitor appears under Old, including Production if it is not explicitly listed. To keep Production in the pipeline, add its monitor node to the children array. Configuration uses exact, case-sensitive monitor titles within one project.

  • direction: required at the root; row or column. On each node it controls the arrangement of that node's children and defaults to column. Rows wrap on smaller screens.
  • items: required ordered array of nodes. Each node has exactly one of monitor (a status card) or group (a heading), plus optional direction and children. A parent card or heading is always above its children.
  • unlisted_group: optional heading for monitors not referenced in the layout. They remain visible after configured nodes, sorted by title. Without a heading they appear in the default grid.
  • Use a group node such as {"group":"Old","direction":"column","children":[{"monitor":"Old Dev"},{"monitor":"Old Testing"}]} for explicit group membership and ordering. Nested groups let you mix rows and columns.
  • Each monitor can appear only once. Limits: 100 total nodes, five levels, and names of 1–255 characters. Unknown properties, duplicate monitor references, or invalid directions are rejected.
  • Configure monitors before they report: missing monitors show an “awaiting data” placeholder, while any available children remain visible. Renaming a monitor requires updating its layout reference.

Grouping controls presentation only. Pipeline's value and status still come from the Pipeline log reports; LogBlazer does not calculate an aggregate status or execute dependencies. Layout settings persist across status updates. Ordinary log ingestion needs no new fields. Heartbeats and browser monitors retain their own sections.

To restore the default flat grid, PUT {"monitor_layout":null}. An empty items array is also valid. In the dashboard editor, enter only the inner layout object (or null); the API request wraps it in monitor_layout. Treat API keys as secrets and keep them in your CI secret store.

Responses

201 Created

{
  "message": "Log received"
}

404 Not Found

Returned when the API key does not match any project.

422 Unprocessable Entity

Returned when validation fails (e.g. missing payload or invalid status value).

Code examples

cURL

curl -X POST https://app.logblazer.com/api/logs/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{"payload": "User signed up", "status": "SUCCESS", "source": "auth-service"}'

JavaScript (fetch)

await fetch("https://app.logblazer.com/api/logs/YOUR_API_KEY", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    payload: "Deployment finished",
    status: "SUCCESS",
    source: "deploy-script"
  })
});

PHP

$response = Http::post("https://app.logblazer.com/api/logs/YOUR_API_KEY", [
    'payload' => 'Database backup completed',
    'status'  => 'SUCCESS',
    'source'  => 'backup-worker',
]);

Python

import requests

requests.post("https://app.logblazer.com/api/logs/YOUR_API_KEY", json={
    "payload": "Cron job failed: timeout after 30s",
    "status": "FAILURE",
    "source": "cron-worker"
})

Bash (minimal)

# Minimum required — just the payload
curl -X POST https://app.logblazer.com/api/logs/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{"payload": "Something happened"}'

LLM-friendly endpoint

Each project's public dashboard has a plain-text endpoint designed for LLM consumption. It returns the current monitors and recent logs as a Markdown document. Public dashboards and the rest of the surface area are covered on the features page.

GET/d/{api_key}/llm

Response

Returns text/plain Markdown with monitors table and recent log entries. No authentication required.

# My Project — Dashboard

Generated: 2026-03-05 14:30:00 UTC

## Monitors (2)

| Monitor | Value | Monitor Status | Updated |
|---|---|---|---|
| API Status | healthy | success | 2026-03-05 14:25:00 |
| Deploy | DEPLOYED | success | 2026-03-05 14:20:00 |

## Recent Logs (3)

| Time | Source | Status | Payload |
|---|---|---|---|
| 2026-03-05 14:25:00 | health-checker | SUCCESS | Health check passed |
| 2026-03-05 14:20:00 | deploy-pipeline | SUCCESS | Production deployed |
| 2026-03-05 14:15:00 | cron | NOTICE | Backup completed |

Usage

curl https://app.logblazer.com/d/YOUR_API_KEY/llm

Use this endpoint to give AI agents and LLMs access to your project's current status. The same public dashboard is also available as a web page at /d/{api_key}.

Heartbeat monitors (cron and worker health checks)

Heartbeats let LogBlazer actively monitor your services. Register a URL and LogBlazer will ping it on a configurable schedule, parse a standardized JSON health response, and alert you by email when checks fail. Results are integrated into your project dashboard as monitors and log entries automatically. For the why-you-would-want-this version, see cron and heartbeat monitoring, or the Healthchecks.io comparison.

Register a heartbeat

POST/api/heartbeats/{api_key}
FieldTypeRequiredDescription
namestringYesDisplay name for the heartbeat (e.g. My App Production). Max 255 characters.
short_namestringNoCompact display name for dashboard cards (e.g. CE Prod). Max 50 characters. Falls back to name if not set.
urlstringYesThe health check URL to ping (e.g. https://myapp.com/api/heartbeat). Max 2048 characters.
auth_tokenstringNoBearer token sent with each health check request. Stored encrypted.
interval_minutesintegerNoHow often to ping, in minutes. Range: 1–60. Default: 3.
timeout_secondsintegerNoRequest timeout. Range: 1–30. Default: 10.
alert_emailsarrayNoEmail addresses to notify on failure. Max 5 addresses.
alert_after_failuresintegerNoConsecutive failures before alerting. Range: 1–10. Default: 2.

Response — 201 Created

{
  "id": "uuid",
  "name": "My App Production",
  "short_name": null,
  "url": "https://myapp.com/api/heartbeat",
  "interval_minutes": 3,
  "timeout_seconds": 10,
  "alert_emails": ["ops@myapp.com"],
  "alert_after_failures": 2,
  "is_active": true,
  "last_status": "UNKNOWN",
  "created_at": "2026-03-09T12:00:00Z"
}

Other heartbeat endpoints

MethodPathDescription
GET/api/heartbeats/{api_key}List all heartbeats for the project.
PATCH/api/heartbeats/{api_key}/{id}Update a heartbeat (partial update).
DELETE/api/heartbeats/{api_key}/{id}Delete a heartbeat. Returns 204.
GET/api/heartbeats/{api_key}/{id}/statusGet current status, checks, and recent results.
POST/api/heartbeats/{api_key}/{id}/checkTrigger an immediate health check.

Health check protocol

Your target application should respond to LogBlazer's health check requests with a JSON body containing an overall status and individual checks. LogBlazer sends a GET request with Accept: application/json and an optional Authorization: Bearer header if configured.

Expected response

{
  "status": "PASS",
  "checks": {
    "database": {
      "status": "PASS",
      "ms": 3,
      "detail": "SELECT 1 succeeded",
      "label": "DB Connection"
    },
    "queue_health": {
      "status": "PASS",
      "detail": "No stale jobs"
    },
    "external_api": {
      "status": "FAIL",
      "ms": 5023,
      "detail": "Timeout after 5s"
    }
  }
}
FieldTypeRequiredDescription
statusstringYesPASS or FAIL. Overall health status.
checksobjectNoMap of check name → check result. When omitted, only the top-level status is used.
checks.*.statusstringYesPASS or FAIL for each check.
checks.*.msintegerNoResponse time in milliseconds.
checks.*.detailstringNoHuman-readable context.
checks.*.labelstringNoCustom display name for this check. Overrides the auto-humanized check key on the dashboard.

HTTP status codes

Return 200 when all checks pass and 503 when one or more checks fail. Any other status code, timeout, or connection error is treated as a complete failure.

Example: registering and checking a heartbeat

# Register a heartbeat
curl -X POST https://app.logblazer.com/api/heartbeats/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Production API",
    "url": "https://myapp.com/api/heartbeat",
    "interval_minutes": 5,
    "alert_emails": ["ops@myapp.com"],
    "alert_after_failures": 3
  }'

# Check status
curl https://app.logblazer.com/api/heartbeats/YOUR_API_KEY/HEARTBEAT_ID/status

# Trigger an immediate check
curl -X POST https://app.logblazer.com/api/heartbeats/YOUR_API_KEY/HEARTBEAT_ID/check

How it works

Automatic monitoring

LogBlazer pings your URL at the configured interval. Each check creates log entries and monitor cards on your dashboard automatically.

Smart alerting

Alerts are sent only after the configured number of consecutive failures. You also get a recovery notification when a heartbeat comes back up.

Browser monitors with CSS-selector assertions

Browser monitors load a page in a real Chromium browser and decide whether it is healthy by looking at what actually rendered. Register a URL and a set of CSS selectors and LogBlazer will run the check on a schedule, recording the outcome together with console errors, failed network requests, and a full-page screenshot when the check fails. Results are integrated into your project dashboard as monitors and log entries automatically, and repeated failures are emailed to you. See browser monitoring for worked examples of pass and fail selectors.

Pass and fail selectors

A browser check does not decide health from the HTTP status alone. Once the page has loaded, LogBlazer polls the rendered DOM — every frame on the page, not just the top document — until one of your selectors matches a visible element or the render budget runs out.

Pass selectors

Evidence the page rendered what it should — the pricing table, the logged-in nav, the search results. The first pass selector to become visible ends the check as PASS. At least one is required: a monitor with no pass selector could never report a pass, so the API rejects it with a 422.

Fail selectors

Evidence something went wrong — an error banner, a stack trace, a maintenance notice. Fail selectors are optional, and they are checked before pass selectors on every poll, so a visible fail selector ends the check as FAIL even when a pass selector is also on the page.

Order of evaluation for one check: a page that fails to load is a FAIL; an HTTP status outside 200–299 is a FAIL recorded without evaluating any selector; otherwise LogBlazer polls fail selectors then pass selectors, roughly ten times a second, until render_timeout_seconds elapses. Nothing matching by then is a FAIL with reason render_timeout.

Create a browser monitor

POST/api/browser-monitors/{api_key}
FieldTypeRequiredDescription
namestringYesDisplay name for the monitor (e.g. Marketing Site). Max 255 characters.
short_namestringNoCompact display name for dashboard cards. Max 50 characters. Falls back to name if not set.
urlstringYesThe page to load in the browser (e.g. https://myapp.com/pricing). Max 2048 characters.
selectorsarrayYesThe CSS selectors that decide pass or fail. Between 1 and 20 entries, at least one of which must be kind: "pass". Array order is the stored order.
selectors.*.selectorstringYesA CSS selector, matched against every frame on the page. Max 1000 characters.
selectors.*.kindstringYespass or fail. Any other value is rejected.
selectors.*.labelstringNoDisplay name for this selector on the dashboard. Max 255 characters.
interval_minutesintegerNo*How often to run the check, in minutes. Range: 5–1440. Default: 5.
render_timeout_secondsintegerNo*How long to keep polling the page for a matching selector after it loads. Range: 5–60. Default: 30.
alert_emailsarrayNoEmail addresses to notify on failure, in addition to the project owner. Max 5 addresses.
alert_after_failuresintegerNo*Consecutive failures before alerting. Range: 1–10. Default: 2.
is_activebooleanNo*Whether the scheduler runs this monitor. Default: true.

* These fields have server-side defaults. Omit the key to take the default, or send a value — but an explicit null is rejected with a 422 rather than falling back to the default.

Response — 201 Created

{
  "browser_monitor": {
    "id": "uuid",
    "project_id": "uuid",
    "name": "Marketing Site",
    "short_name": "mkt",
    "url": "https://myapp.com/pricing",
    "interval_minutes": 15,
    "render_timeout_seconds": 45,
    "alert_emails": ["ops@myapp.com"],
    "alert_after_failures": 3,
    "consecutive_failures": 0,
    "last_checked_at": null,
    "last_status": "UNKNOWN",
    "is_active": true,
    "created_at": "2026-03-09T12:00:00Z",
    "updated_at": "2026-03-09T12:00:00Z",
    "is_stale": false,
    "selectors": [
      {
        "id": "uuid",
        "browser_monitor_id": "uuid",
        "selector": "#pricing-table",
        "kind": "pass",
        "label": "Pricing table",
        "position": 0,
        "created_at": "2026-03-09T12:00:00Z",
        "updated_at": "2026-03-09T12:00:00Z"
      },
      {
        "id": "uuid",
        "browser_monitor_id": "uuid",
        "selector": ".error-banner",
        "kind": "fail",
        "label": "Error banner",
        "position": 1,
        "created_at": "2026-03-09T12:00:00Z",
        "updated_at": "2026-03-09T12:00:00Z"
      }
    ],
    "latest_result": null
  }
}

Selector position is assigned from the array order, never taken from the request, and last_status stays UNKNOWN until the first check runs. is_stale is derived, not stored: it turns true when an active monitor has gone longer than twice its interval without a check.

Other browser monitor endpoints

MethodPathDescription
GET/api/browser-monitors/{api_key}List all browser monitors for the project, newest first, each with its selectors and latest result.
PATCH/api/browser-monitors/{api_key}/{id}Update a browser monitor (partial update).
DELETE/api/browser-monitors/{api_key}/{id}Delete a browser monitor along with its selectors and results. Returns 204 with an empty body.
GET/api/browser-monitors/{api_key}/{id}/statusGet the monitor, its latest result, and up to 100 recent results.
POST/api/browser-monitors/{api_key}/{id}/checkQueue an immediate check. Returns 202.

Every response other than the delete returns the monitor wrapped in a browser_monitor key; the list endpoint wraps its array in browser_monitors. A PATCH is a true partial update: omitted fields are left alone. selectors is the exception — supply it and it replaces the entire set, so selector ids are not stable across an update, and the replacement must still contain at least one pass selector. Omit selectors to leave them untouched.

Check results

Every check writes a result row. The status endpoint returns three keys — browser_monitor with its selectors, latest_result, and recent_results (up to 100, newest first). The list, create, update, and check responses embed the newest one as latest_result, which is null until a check has run.

{
  "id": "uuid",
  "browser_monitor_id": "uuid",
  "status": "FAIL",
  "error_reason": "fail_selector_matched",
  "status_code": 200,
  "matched_selector_id": "uuid",
  "matched_frame_url": "https://myapp.com/pricing",
  "duration_ms": 2318,
  "console_errors": ["TypeError: undefined is not a function"],
  "network_failures": [
    { "url": "https://myapp.com/api/plans", "status": 500, "method": "GET" }
  ],
  "screenshot_path": "browser-monitor-screenshots/uuid/uuid.png",
  "error_message": null,
  "created_at": "2026-03-09T12:00:00Z"
}
FieldTypeDescription
statusstringPASS or FAIL.
error_reasonstringWhy the check failed. null on a pass. See the table above.
status_codeintegerHTTP status of the main document response. null when navigation never completed.
matched_selector_idstringId of the selector that ended the check, pass or fail. null when nothing matched.
matched_frame_urlstringURL of the frame the matching element was found in — useful when the match came from an iframe.
duration_msintegerWall-clock time for the whole check.
console_errorsarrayBrowser console messages of type error captured during the check.
network_failuresarrayRequests that returned a status of 400 or above, each as {url, status, method}.
screenshot_pathstringStored full-page screenshot, captured when a check fails after the page loaded. null on a pass, and on a failure where navigation never completed.
error_messagestringFree-text detail for navigation and subprocess errors. null otherwise.

Failure reasons

error_reasonMeaning
nullThe check passed — a pass selector became visible.
fail_selector_matchedA fail selector became visible. matched_selector_id identifies which one.
render_timeoutNo selector matched before render_timeout_seconds elapsed.
http_statusThe page responded with a status outside 200–299. Selectors are never evaluated. status_code carries the status.
navigation_failedThe browser could not load the URL at all — DNS failure, refused connection, or navigation timeout. error_message carries the detail.
subprocess_errorThe browser process itself failed or exceeded its own timeout. error_message carries the detail.

Example: creating and checking a browser monitor

# Create a browser monitor
curl -X POST https://app.logblazer.com/api/browser-monitors/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Marketing Site",
    "url": "https://myapp.com/pricing",
    "interval_minutes": 15,
    "render_timeout_seconds": 45,
    "alert_emails": ["ops@myapp.com"],
    "alert_after_failures": 3,
    "selectors": [
      { "selector": "#pricing-table", "kind": "pass", "label": "Pricing table" },
      { "selector": ".plan-card", "kind": "pass" },
      { "selector": ".error-banner", "kind": "fail", "label": "Error banner" }
    ]
  }'

# Read current status, latest result, and recent results
curl https://app.logblazer.com/api/browser-monitors/YOUR_API_KEY/MONITOR_ID/status

# Queue an immediate check
curl -X POST https://app.logblazer.com/api/browser-monitors/YOUR_API_KEY/MONITOR_ID/check

How it works

Checks are queued, not inline

A browser check holds a Chromium for tens of seconds, so it runs on a queue. The trigger endpoint returns 202 as soon as the job is queued — the latest_result in that response is still the previous run, so poll the status endpoint for the new one. Triggering a monitor that already has a check in flight is deduplicated.

Smart alerting

A down alert goes out when consecutive_failures reaches alert_after_failures, to the project owner plus every address in alert_emails. A recovery alert is sent only after a monitor that actually alerted comes back, so a single transient failure never produces a pair of emails.

Quick reference

Authentication

API key in the URL path. No headers or tokens needed.

Content type

Always application/json.

Status values

SUCCESS, FAILURE, WARNING, NOTICE

Monitor types

status, boolean, number, text

Monitor status

success, failure, warning

Rate limits

Browser monitor endpoints: 60 requests per minute. Log and heartbeat endpoints are unlimited.

Heartbeat intervals

1–60 minutes (default 3)

Health check response

200 = PASS, 503 = FAIL, other = failure

Browser monitor intervals

5–1440 minutes (default 5)

Selector kinds

pass, fail — at least one pass per monitor

Send your first log in under 60 seconds

Free forever plan, no credit card. One POST and it is on your dashboard.