PiAlert provides a REST API for external integrations to access monitoring data. Use API keys to authenticate and poll alert status for automation, webhooks, IoT devices, and custom applications.
All API requests require an API key passed in the x-api-key header.
- Log in to your PiAlert dashboard
- Navigate to Settings
- Scroll to API Keys section
- Click Generate New API Key
- Give your key a name (e.g., "Home Assistant", "Node-RED")
- Copy the key immediately (it won't be shown again)
Include the API key in the x-api-key header with every request:
curl -H "x-api-key: YOUR_API_KEY_HERE" \
http://your-server:8000/api/v1/alert-statusEndpoint: GET /api/v1/alert-status
Description: Lightweight polling endpoint that returns current alert state and failing targets. Optimized for 10-30 second polling intervals.
Authentication: Required (API key)
Request Example:
curl -H "x-api-key: your-api-key-here" \
http://localhost:8000/api/v1/alert-statusResponse (No Alerts):
{
"alert": false,
"failing_targets": [],
"failing_count": 0,
"timestamp": "2025-10-21T21:14:18.317325+00:00"
}Response (With Alerts):
{
"alert": true,
"failing_targets": [
{
"name": "Production Server",
"status": "down",
"failures": 5,
"threshold": 3
},
{
"name": "Database",
"status": "down",
"failures": 4,
"threshold": 3
}
],
"failing_count": 2,
"timestamp": "2025-10-21T21:32:15.123456+00:00"
}Response Fields:
| Field | Type | Description |
|---|---|---|
alert |
boolean | true if ANY target is currently failing (exceeds threshold), false if all targets are OK |
failing_targets |
array | List of targets currently exceeding their failure threshold |
failing_count |
integer | Quick count of failing targets (same as failing_targets.length) |
timestamp |
string | ISO 8601 UTC timestamp of when the status was generated |
Failing Target Object:
| Field | Type | Description |
|---|---|---|
name |
string | Display name of the target |
status |
string | Current status (always "down" for failing targets) |
failures |
integer | Current consecutive failure count |
threshold |
integer | Number of failures required to trigger an alert |
Error Responses:
// 401 Unauthorized - Missing API key
{
"detail": "Missing API key in x-api-key header"
}
// 401 Unauthorized - Invalid API key
{
"detail": "Invalid or disabled API key"
}
// 429 Too Many Requests - Rate limit exceeded (valid key)
{
"detail": "Rate limit exceeded. Try again in 42 seconds."
}
// Headers: Retry-After: 42
// 429 Too Many Requests - Too many failed auth attempts
{
"detail": "Too many failed authentication attempts. Try again in 60 seconds."
}
// Headers: Retry-After: 60
// 500 Internal Server Error
{
"detail": "Unable to fetch alert status"
}Notes:
- Targets must exceed their configured
failure_thresholdto appear infailing_targets - Acknowledged alerts are excluded from the response
- Disabled targets are excluded from the response
- Response size typically <500 bytes
- Rate limit: 120 requests/minute per API key (see Rate Limiting section below)
Control a physical relay based on alert state:
#!/usr/bin/env python3
import requests
import RPi.GPIO as GPIO
import time
RELAY_PIN = 17 # GPIO pin number
API_URL = "http://your-server:8000/api/v1/alert-status"
API_KEY = "your-api-key-here"
POLL_INTERVAL = 30 # seconds
GPIO.setmode(GPIO.BCM)
GPIO.setup(RELAY_PIN, GPIO.OUT)
while True:
try:
response = requests.get(
API_URL,
headers={"x-api-key": API_KEY},
timeout=5
)
if response.status_code == 200:
data = response.json()
if data["alert"]:
GPIO.output(RELAY_PIN, GPIO.HIGH) # Turn ON
print(f"ALERT: {data['failing_count']} targets down")
else:
GPIO.output(RELAY_PIN, GPIO.LOW) # Turn OFF
print("All systems operational")
except Exception as e:
print(f"Error: {e}")
time.sleep(POLL_INTERVAL)Add a REST sensor to Home Assistant:
# configuration.yaml
rest:
- resource: "http://your-server:8000/api/v1/alert-status"
headers:
x-api-key: "your-api-key-here"
scan_interval: 30
sensor:
- name: "PiAlert Status"
value_template: "{{ 'Alert' if value_json.alert else 'OK' }}"
json_attributes:
- failing_count
- failing_targets
- timestamp
binary_sensor:
- platform: template
sensors:
pialert_alert:
friendly_name: "PiAlert Alert"
value_template: "{{ state_attr('sensor.pialert_status', 'alert') }}"
device_class: problemUse the HTTP Request node:
{
"method": "GET",
"url": "http://your-server:8000/api/v1/alert-status",
"headers": {
"x-api-key": "your-api-key-here"
}
}Then use a Function node to process the response:
if (msg.payload.alert) {
msg.payload = {
text: `⚠️ ${msg.payload.failing_count} targets are down!`,
targets: msg.payload.failing_targets
};
return msg;
}
return null; // No alertPython script to send alerts to Discord/Slack:
import requests
import time
PIALERT_URL = "http://your-server:8000/api/v1/alert-status"
PIALERT_API_KEY = "your-api-key-here"
DISCORD_WEBHOOK = "https://discord.com/api/webhooks/..."
last_alert_state = False
while True:
response = requests.get(
PIALERT_URL,
headers={"x-api-key": PIALERT_API_KEY}
)
if response.status_code == 200:
data = response.json()
# Alert state changed
if data["alert"] != last_alert_state:
if data["alert"]:
targets = "\n".join([
f"- {t['name']} ({t['failures']}/{t['threshold']} failures)"
for t in data["failing_targets"]
])
message = f"🚨 **Alert!** {data['failing_count']} targets are down:\n{targets}"
else:
message = "✅ All systems recovered!"
# Send to Discord
requests.post(DISCORD_WEBHOOK, json={"content": message})
last_alert_state = data["alert"]
time.sleep(30)Simple bash script for cron jobs or monitoring:
#!/bin/bash
API_URL="http://your-server:8000/api/v1/alert-status"
API_KEY="your-api-key-here"
response=$(curl -s -H "x-api-key: $API_KEY" "$API_URL")
alert=$(echo "$response" | jq -r '.alert')
count=$(echo "$response" | jq -r '.failing_count')
if [ "$alert" = "true" ]; then
echo "ALERT: $count targets are down"
echo "$response" | jq -r '.failing_targets[] | "- \(.name): \(.failures)/\(.threshold) failures"'
exit 1
else
echo "OK: All systems operational"
exit 0
fiUse a webhook URL to trigger IFTTT/Zapier:
import requests
PIALERT_URL = "http://your-server:8000/api/v1/alert-status"
PIALERT_API_KEY = "your-api-key-here"
IFTTT_WEBHOOK = "https://maker.ifttt.com/trigger/{event}/with/key/{key}"
response = requests.get(
PIALERT_URL,
headers={"x-api-key": PIALERT_API_KEY}
)
if response.status_code == 200:
data = response.json()
if data["alert"]:
requests.post(IFTTT_WEBHOOK, json={
"value1": data["failing_count"],
"value2": ", ".join([t["name"] for t in data["failing_targets"]]),
"value3": data["timestamp"]
})- Recommended: 30 seconds
- Minimum: 10 seconds (avoid excessive load)
- Maximum: 5 minutes (for timely alerts)
Always handle network errors and API failures gracefully:
try:
response = requests.get(url, headers=headers, timeout=5)
response.raise_for_status()
data = response.json()
except requests.exceptions.RequestException as e:
print(f"API Error: {e}")
# Keep last known state or use safe default
except ValueError as e:
print(f"Invalid JSON: {e}")- Use HTTPS in production to encrypt API keys in transit
- Store API keys securely (environment variables, secret managers)
- Never commit API keys to version control
- Rotate keys if compromised
- Use unique keys per integration (easier to revoke)
API endpoints are protected by rate limiting to prevent abuse:
- 120 requests per minute per API key
- Allows polling every 30 seconds with plenty of headroom
- Status code:
429 Too Many Requestswhen exceeded - Response includes
Retry-Afterheader (seconds until limit resets)
- 10 failed authentication attempts per minute per IP address
- Prevents brute force attacks on API keys
- Status code:
429 Too Many Requestswhen exceeded - Response includes
Retry-Afterheader
- Recommended polling interval: 30 seconds (allows 120 requests/hour)
- Minimum polling interval: 10 seconds (still well within limits)
- Handle 429 responses: Check
Retry-Afterheader and wait before retrying - Use exponential backoff on errors
- Cache responses when possible to reduce request frequency
{
"detail": "Rate limit exceeded. Try again in 42 seconds."
}Response Headers:
Retry-After: Number of seconds until rate limit resetsStatus Code: 429 Too Many Requests
- List Keys: Settings → API Keys
- Create Key: Click "Generate New API Key"
- Disable Key: Click the pause icon
- Delete Key: Click the trash icon (cannot be undone)
Each key tracks:
- Name: Friendly identifier
- Created: When the key was generated
- Last Used: Most recent API call
- Usage Count: Total number of requests
- Status: Active or Disabled
Make sure you're including the header:
# ✅ Correct
curl -H "x-api-key: YOUR_KEY" http://...
# ❌ Wrong
curl http://...Check that:
- Key is copied correctly (no extra spaces)
- Key hasn't been deleted
- Key is enabled (not paused)
- You're using the full key value
- Verify PiAlert is running:
docker compose ps - Check the correct port (default: 8000)
- Ensure firewall allows connections
- Use correct hostname/IP address
If failing_targets is always empty:
- Check that targets are configured in PiAlert
- Verify targets are enabled
- Ensure failure thresholds are properly set
- Targets must actually be failing to appear
Current API version: v1
All endpoints are prefixed with /api/v1/. Future versions will use /api/v2/, etc.
Breaking changes will only be introduced in new major versions. The v1 API will remain stable.
- GitHub Issues: https://github.com/anthropics/claude-code/issues
- Documentation: https://docs.claude.com/
- PiAlert Dashboard: Check Settings → API Keys for usage statistics
- Physical Indicators: LED strips, alarm sirens, status lights
- Home Automation: Trigger scenes, send notifications, control devices
- CI/CD Pipelines: Block deployments if monitoring shows issues
- Dashboards: Grafana, custom web dashboards
- Mobile Apps: iOS shortcuts, Tasker (Android)
- Voice Assistants: Alexa, Google Home custom skills
- Email/SMS: Send alerts via Twilio, SendGrid
- Incident Management: Auto-create PagerDuty/Opsgenie incidents
API Version: 1.0 Last Updated: October 2025