HB
Heartbeat

Application pulse

Measure what matters, without the noise.

Heartbeat lets you record lightweight events from your application and view their rhythm over time. Track tiny interactions or critical milestones with the same endpoint.

Free-text events

Name events any way you like, from auth flows to tiny function calls.

Flexible timing

Send heartbeats with a custom timestamp when long tasks finish.

Back to home

Integration Guide

Complete API reference and code examples for integrating Hartslag into your applications.

Download Markdown AI-Agent Optimized

Hartslag Integration Guide (Heartbeat API)

Note: This guide focuses on safe, low-impact event tracking. Heartbeats should never block user requests or break your app.

Overview

Hartslag is a lightweight event tracking service. You send timestamped heartbeats whenever something meaningful happens (user activity, background jobs, business events), and Hartslag aggregates counts over time.

What is a “heartbeat”?

A heartbeat is a single, timestamped occurrence of an event:

  • Real-time activity monitoring: Track actions and system events as they happen
  • Aggregate reporting: View event counts aggregated by time periods (today, week, month, total)
  • Flexible event tracking: Use any event name (recommended: kebab-case)
  • Weighted metrics: Use weight to track values like durations, file sizes, or amounts

How It Works

  1. Your app sends a POST request to the API with an event name (and optional metadata)
  2. Hartslag records the heartbeat
  3. You view aggregated metrics in the dashboard
  4. You can export historical data as CSV

Base URL: http://hartslag.no

The base URL is the URL of your Hartslag instance. When viewing the hosted docs, the site will typically show the correct base URL for that environment.

Quick Start

Important: Send heartbeats asynchronously (queue/background) whenever possible. Tracking must never slow down user requests.

1. Get Your API Token

  1. Log in to Hartslag
  2. Create or select an Application
  3. Copy the API token (bearer token)

2. Send Your First Heartbeat

BASE_URL="http://hartslag.no"
TOKEN="YOUR_TOKEN_HERE"

curl -X POST "$BASE_URL/api/v1/heartbeat" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "event": "user-login",
    "weight": 1,
    "user_id": 123,
    "created_at": "2024-01-17T10:30:00Z"
  }'

Success: 201 Created

Response body (current): empty JSON (e.g. []).

API Reference

POST /api/v1/heartbeat

Records a single heartbeat.

Headers

  • Authorization: Bearer {token} (required)
  • Content-Type: application/json (required)

Body parameters

Parameter Type Required Description
event string Yes Event name. Recommended: kebab-case (e.g. user-login).
weight integer No Default: 1. Use for weighted metrics (durations, amounts, etc.).
user_id integer No Optional user identifier for per-user activity.
created_at string/date No Optional timestamp. The API accepts Laravel “date” formats. Recommended: ISO 8601 / RFC 3339 (e.g. 2024-01-17T10:30:00Z).

Success response

  • Status: 201 Created
  • Body: empty JSON (current)

Error responses

  • 401 Unauthorized: Missing/invalid token

    {"error": "Unauthorized"}
    
  • 422 Unprocessable Entity: Validation error

    {
      "message": "The event field is required.",
      "errors": {
        "event": ["The event field is required."]
      }
    }
    

Idempotency / retries

Requests are not idempotent. If your client retries the same request, it may be counted multiple times.

If this matters for a specific event, de-duplicate on the client side (or accept small overcounting for non-critical metrics).

Code Examples

PHP (Laravel) — recommended pattern

Store base URL + token in config, and send via queue/job.

use Illuminate\Support\Facades\Http;

class HartslagClient
{
    public function send(string $event, int $weight = 1, ?int $userId = null, $createdAt = null): void
    {
        $baseUrl = rtrim(config('services.hartslag.url'), '/');
        $token = config('services.hartslag.token');

        // Never let tracking break the main flow.
        try {
            Http::withToken($token)
                ->acceptJson()
                ->asJson()
                ->connectTimeout(2)
                ->timeout(5)
                ->retry(2, 150, throw: false)
                ->post("{$baseUrl}/api/v1/heartbeat", [
                    'event' => $event,
                    'weight' => $weight,
                    'user_id' => $userId,
                    'created_at' => $createdAt ?? now()->toISOString(),
                ]);
        } catch (\Throwable $e) {
            \Log::warning('Hartslag heartbeat failed', ['error' => $e->getMessage()]);
        }
    }
}

Config (config/services.php):

'hartslag' => [
    'url' => env('HARTSLAG_URL', 'http://hartslag.no'),
    'token' => env('HARTSLAG_TOKEN'),
],

Queue it (example):

Laravel best practice is to use a dedicated Job that implements ShouldQueue.

php artisan make:job SendHartslagHeartbeat
SendHartslagHeartbeat::dispatch('user-registered', auth()->id())
    ->onQueue('low');

JavaScript (Node.js)

const axios = require('axios');

async function sendHeartbeat(baseUrl, token, payload) {
  try {
    const res = await axios.post(
      `${baseUrl.replace(/\/$/, '')}/api/v1/heartbeat`,
      payload,
      {
        timeout: 2000,
        headers: {
          Authorization: `Bearer ${token}`,
          'Content-Type': 'application/json',
        },
      }
    );

    return res.status === 201;
  } catch (err) {
    // Log and continue; tracking must be non-critical.
    return false;
  }
}

Browser/Frontend

Do not call the Hartslag API directly from the browser (you would expose your token).

Recommended pattern:

  1. Frontend → your backend (no Hartslag token)
  2. Backend → Hartslag API (token stored server-side)

Best Practices

Event naming

Recommended: descriptive, kebab-case event names.

Good:

  • user-login
  • payment-completed
  • email-sent

Avoid:

  • event1, test, foo
  • UserLogin

Weight usage

Use weight for meaningful metrics:

// Response time in ms
$ms = 150;
$client->send('api-call', weight: $ms);

// Payment amount in cents
$client->send('payment-completed', weight: 1999, userId: $user->id);

Time handling (created_at)

  • Omit created_at for “now” (recommended)
  • Use ISO 8601 / RFC 3339 when backdating
  • Avoid future timestamps unless you intentionally want that behavior

Security

  • Keep tokens server-side (env vars / secrets manager)
  • Use HTTPS
  • Rotate tokens when needed

Troubleshooting

401 Unauthorized

  • Check bearer token
  • Check Authorization: Bearer ... format

422 Validation Error

  • Ensure event is present and non-empty
  • weight and user_id must be integers if provided
  • Use a valid date for created_at (ISO 8601 recommended)

Timeouts / flaky networks

  • Use short timeouts (2–5s)
  • Retry a small number of times
  • Prefer queue/background for non-critical tracking

Version

API Version: v1

Need help? Contact your system administrator or log in to your dashboard