API Reference
Full REST API documentation for Unsparing. Authenticate, create monitors, manage alerts, and automate everything.
Base URL
https://api.unsparing.dev/api/v1All API requests use this base URL. Responses are JSON.
Authentication
Unsparing uses Bearer token authentication. Include your API key in the Authorization header:
curl -H "Authorization: Bearer YOUR_API_KEY" \
https://api.unsparing.dev/api/v1/monitorsCreating an API Key
- Go to Settings → API Keys
- Click Create API Key
- Give it a name (e.g., "CI/CD Pipeline")
- Select the permissions (read, write, or both)
- Copy the key — it's shown only once
API keys are available on Homelabber (read-only) and Teams/Agency (full access) plans.
Response Format
All responses follow a consistent format:
Success Response
{
"data": { ... },
"meta": {
"page": 1,
"per_page": 25,
"total": 42
}
}Error Response
{
"error": {
"code": "validation_error",
"message": "The given data was invalid.",
"details": {
"url": ["The url field is required."]
}
}
}HTTP Status Codes
| Code | Meaning |
|---|---|
| 200 | Success |
| 201 | Created |
| 204 | No content (deleted) |
| 400 | Bad request / validation error |
| 401 | Unauthorized (invalid or missing API key) |
| 403 | Forbidden (insufficient permissions) |
| 404 | Not found |
| 429 | Rate limited (retry after Retry-After header) |
| 500 | Internal server error |
Rate Limiting
API requests are rate-limited per plan:
| Plan | Requests/minute |
|---|---|
| Free | 60 |
| Homelabber | 120 |
| Teams | 300 |
| Agency | 600 |
Rate limit headers are included in every response:
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 295
X-RateLimit-Reset: 1716028800When rate limited, the response includes a Retry-After header (in seconds).
Cron Tasks
List Cron Tasks
GET /cron/taskscurl -H "Authorization: Bearer $API_KEY" \
https://api.unsparing.dev/api/v1/cron/tasksResponse:
{
"data": [
{
"id": "task_abc123",
"name": "Backup Database",
"schedule": "0 2 * * *",
"grace_period": 300,
"status": "healthy",
"last_ping": "2025-05-18T01:58:00Z",
"next_expected": "2025-05-19T02:00:00Z",
"created_at": "2025-01-15T10:30:00Z"
}
]
}Create a Cron Task
POST /cron/taskscurl -X POST -H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Backup Database",
"schedule": "0 2 * * *",
"grace_period": 300,
"timezone": "UTC"
}' \
https://api.unsparing.dev/api/v1/cron/tasksPing a Cron Task
POST /ping/{task_id}curl https://api.unsparing.dev/api/v1/ping/task_abc123No authentication required — ping URLs are public but unique.
Delete a Cron Task
DELETE /cron/tasks/{task_id}DNS Watchers
List DNS Watchers
GET /dns/watchersCreate a DNS Watcher
POST /dns/watcherscurl -X POST -H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"domain": "example.com",
"record_type": "A",
"expected_value": "1.2.3.4",
"check_interval": 300
}' \
https://api.unsparing.dev/api/v1/dns/watchersDelete a DNS Watcher
DELETE /dns/watchers/{watcher_id}SSL Monitors
List SSL Monitors
GET /ssl/monitorsCreate an SSL Monitor
POST /ssl/monitorscurl -X POST -H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"hostname": "example.com",
"port": 443,
"warning_days": [30, 14, 7]
}' \
https://api.unsparing.dev/api/v1/ssl/monitorsDelete an SSL Monitor
DELETE /ssl/monitors/{monitor_id}Uptime Monitors
List Uptime Monitors
GET /uptime/monitorsCreate an Uptime Monitor
POST /uptime/monitorscurl -X POST -H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "https",
"url": "https://api.example.com/health",
"check_interval": 60,
"expected_status": [200],
"timeout": 10,
"keyword": "healthy"
}' \
https://api.unsparing.dev/api/v1/uptime/monitorsPause/Resume a Monitor
POST /uptime/monitors/{monitor_id}/pause
POST /uptime/monitors/{monitor_id}/resumeDelete an Uptime Monitor
DELETE /uptime/monitors/{monitor_id}Dashboard & Metrics
Get Dashboard Summary
GET /dashboardReturns a summary of all monitors, recent alerts, and metrics.
curl -H "Authorization: Bearer $API_KEY" \
https://api.unsparing.dev/api/v1/dashboardResponse:
{
"data": {
"summary": {
"total_monitors": 12,
"healthy": 10,
"degraded": 1,
"failing": 1
},
"metrics": {
"uptime": { "percentage": 99.95 },
"latency": { "p50": 120, "p95": 340 },
"cron": { "success_rate": 98.5 }
},
"recent_activity": {
"cron_executions": [],
"dns_alerts": [],
"ssl_warnings": [],
"uptime_events": []
}
}
}Webhooks
List Webhooks
GET /webhooksCreate a Webhook
POST /webhookscurl -X POST -H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://api.example.com/webhooks/unsparing",
"events": ["monitor.failed", "monitor.recovered", "ssl.expiring"],
"secret": "whsec_your_secret_here"
}' \
https://api.unsparing.dev/api/v1/webhooksDelete a Webhook
DELETE /webhooks/{webhook_id}Investigations
Investigations group related alerts into a timeline for incident management.
List Investigations
GET /investigationsCreate an Investigation
POST /investigationscurl -X POST -H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Production API downtime",
"monitor_ids": ["mon_abc123", "mon_def456"],
"severity": "critical"
}' \
https://api.unsparing.dev/api/v1/investigationsUtility Tools
Unsparing includes free utility tools accessible without authentication:
DNS Lookup
GET /tools/dns-lookup?domain=example.com&type=APassword Generator
GET /tools/password-generator?length=24&numbers=true&symbols=trueURL Shortener
POST /tools/shortencurl -X POST -H "Content-Type: application/json" \
-d '{"url": "https://example.com/very-long-url"}' \
https://api.unsparing.dev/api/v1/tools/shortenQR Code Generator
GET /tools/qr?content=https://example.com&size=256API Keys
List API Keys
GET /api-keysCreate an API Key
POST /api-keyscurl -X POST -H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "CI/CD Pipeline",
"permissions": ["read"]
}' \
https://api.unsparing.dev/api/v1/api-keysRevoke an API Key
DELETE /api-keys/{key_id}Error Handling Best Practices
- Always check the status code — don't assume 200
- Handle 429 rate limits — use the
Retry-Afterheader - Implement exponential backoff — for 5xx errors, retry with increasing delays
- Validate responses — check the
datafield exists before accessing nested properties - Log errors — include the request ID from
X-Request-IDheader in your logs
import requests
import time
import os
API_KEY = os.environ["UNSPARING_API_KEY"]
BASE_URL = "https://api.unsparing.dev/api/v1"
def api_request(method, path, **kwargs):
headers = {"Authorization": f"Bearer {API_KEY}"}
max_retries = 3
for attempt in range(max_retries):
response = requests.request(
method,
f"{BASE_URL}{path}",
headers=headers,
**kwargs
)
if response.status_code == 429:
retry_after = int(response.headers.get("Retry-After", 60))
time.sleep(retry_after)
continue
if response.status_code >= 500:
if attempt < max_retries - 1:
time.sleep(2 ** attempt)
continue
response.raise_for_status()
return response.json()
raise Exception(f"Request failed after {max_retries} attempts")