Ionhour Docs

Signals API

Send heartbeat pings, query signal history, and subscribe to real-time updates via SSE.

Signals are the heartbeat of IonHour's monitoring. Every ping your service sends creates a signal record. IonHour uses signals to determine check status, detect outages, and track uptime.

Send a Heartbeat (GET)

GET /signals/ping/:token

The simplest way to send a heartbeat. No authentication required.

curl https://app.failsignal.com/api/signals/ping/YOUR_TOKEN

Response

{"message": "OK"}

IonHour captures the source IP address and user agent with each ping.

Send a Heartbeat with Payload (POST)

POST /signals/ping/:token

Send a heartbeat with a JSON payload for additional context. No authentication required.

curl -X POST https://app.failsignal.com/api/signals/ping/YOUR_TOKEN \
  -H "Content-Type: application/json" \
  -d '{
    "status": "completed",
    "rows_processed": 1500,
    "duration_ms": 4200
  }'

Payload Limits

  • Maximum payload size: 10 KB
  • Payload is stored with the signal and visible in the signal history.

Reporting Dependencies

Include a dependencies array in the payload to report the health of external services your application depends on:

curl -X POST https://app.failsignal.com/api/signals/ping/YOUR_TOKEN \
  -H "Content-Type: application/json" \
  -d '{
    "dependencies": [
      {"name": "PostgreSQL", "status": "ok"},
      {"name": "Redis", "status": "down"}
    ]
  }'

When a dependency is reported as down, IonHour creates a DEPENDENCY_DOWN incident for the check. See Dependencies for details.

What Happens When a Ping is Received

Each ping triggers the full monitoring pipeline:

  1. Signal created — stored in MongoDB with type SUCCESS.
  2. Check status updatedlastPingAt and nextDueAt are recalculated.
  3. Incident resolution — if the check was DOWN, active incidents are resolved.
  4. Dependency evaluation — if the check has dependencies, their impact is assessed.
  5. SSE broadcast — connected clients receive the signal in real time.

Signal History

GET /signals/token/:token

Returns paginated signal history for a check. Requires authentication.

Query Parameters

ParameterTypeDescription
pagenumberPage number (default: 1)
limitnumberItems per page (default: 20)
startDateISO stringFilter signals after this date
endDateISO stringFilter signals before this date

Example

curl -H "Authorization: Bearer ionh_your_key" \
  "https://app.failsignal.com/api/signals/token/YOUR_TOKEN?limit=10"

Signal Types

Each signal has a type indicating how it was created:

TypeDescription
SUCCESSA heartbeat was received (from a ping)
SUSPECTThe check is overdue — system-generated when the check transitions to LATE
FAILThe check has failed — system-generated when the check transitions to DOWN
DEPLOYMENTA deployment window started or ended — includes deployment metadata

Real-Time Updates (SSE)

GET /signals/sse

Subscribe to a Server-Sent Events stream for real-time signal and check updates. Requires authentication.

Query Parameters

ParameterTypeDescription
tokenstringOptional check token to filter events to a single check

Example

curl -N -H "Authorization: Bearer ionh_your_key" \
  "https://app.failsignal.com/api/signals/sse?token=YOUR_TOKEN"

Event Types

The SSE stream emits these event types:

EventDescription
Signal eventsNew signals for the subscribed check (or all user's checks if no token)
Check updatesStatus changes on checks
HeartbeatKeep-alive pings every 15 seconds

Connection

  • The SSE connection stays open until the client disconnects.
  • Heartbeat events are sent every 15 seconds to keep the connection alive.
  • If no token is provided, the stream includes events for all checks accessible to the authenticated user.
  • Rate limit: 30 connections per 60 seconds.

Client Example

const eventSource = new EventSource(
  'https://app.failsignal.com/api/signals/sse?token=YOUR_TOKEN',
  {
    headers: {
      'Authorization': 'Bearer ionh_your_key'
    }
  }
);

eventSource.onmessage = (event) => {
  const data = JSON.parse(event.data);
  console.log('Signal received:', data);
};

eventSource.onerror = (error) => {
  console.error('SSE connection error:', error);
};