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:
- Signal created — stored in MongoDB with type
SUCCESS. - Check status updated —
lastPingAtandnextDueAtare recalculated. - Incident resolution — if the check was DOWN, active incidents are resolved.
- Dependency evaluation — if the check has dependencies, their impact is assessed.
- 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
| Parameter | Type | Description |
|---|---|---|
page | number | Page number (default: 1) |
limit | number | Items per page (default: 20) |
startDate | ISO string | Filter signals after this date |
endDate | ISO string | Filter 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:
| Type | Description |
|---|---|
SUCCESS | A heartbeat was received (from a ping) |
SUSPECT | The check is overdue — system-generated when the check transitions to LATE |
FAIL | The check has failed — system-generated when the check transitions to DOWN |
DEPLOYMENT | A 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
| Parameter | Type | Description |
|---|---|---|
token | string | Optional 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:
| Event | Description |
|---|---|
| Signal events | New signals for the subscribed check (or all user's checks if no token) |
| Check updates | Status changes on checks |
| Heartbeat | Keep-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
tokenis 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);
};