Python
Use the requests library to interact with the Sentro API from Python. No dedicated SDK is needed.
Install
pip install requests
Client Wrapper
Create a reusable API client class:
# sentro.py
import requests
from typing import Optional
from urllib.parse import urlencode
BASE_URL = "https://api.sentro.dev/v1"
class SentroError(Exception):
"""Raised when the API returns an error response."""
def __init__(self, status_code: int, code: str, message: str):
self.status_code = status_code
self.code = code
self.message = message
super().__init__(f"API Error [{status_code}]: {message}")
class SentroClient:
def __init__(self, api_key: str):
self.session = requests.Session()
self.session.headers.update(
{
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json",
}
)
def _request(self, method: str, path: str, **kwargs) -> dict:
url = f"{BASE_URL}{path}"
response = self.session.request(method, url, **kwargs)
body = response.json()
if not response.ok:
error = body.get("error", {})
raise SentroError(
status_code=response.status_code,
code=error.get("code", "UNKNOWN"),
message=error.get("message", "Unknown error"),
)
return body
# ── Monitors ──────────────────────────────────────
def list_monitors(self) -> dict:
"""List all monitors for your organization."""
return self._request("GET", "/monitors")
def get_monitor(self, monitor_id: str) -> dict:
"""Get a single monitor with its latest checks."""
return self._request("GET", f"/monitors/{monitor_id}")
def create_monitor(
self,
name: str,
url: str,
method: str = "GET",
interval_seconds: int = 60,
timeout_seconds: int = 30,
expected_status_code: int = 200,
follow_redirects: bool = True,
headers: Optional[dict] = None,
) -> dict:
"""Create a new monitor."""
payload = {
"name": name,
"url": url,
"method": method,
"intervalSeconds": interval_seconds,
"timeoutSeconds": timeout_seconds,
"expectedStatusCode": expected_status_code,
"followRedirects": follow_redirects,
}
if headers:
payload["headers"] = headers
return self._request("POST", "/monitors", json=payload)
def update_monitor(self, monitor_id: str, **kwargs) -> dict:
"""Update an existing monitor. Pass only the fields to change."""
# Convert snake_case kwargs to camelCase for the API
field_map = {
"name": "name",
"url": "url",
"method": "method",
"interval_seconds": "intervalSeconds",
"timeout_seconds": "timeoutSeconds",
"expected_status_code": "expectedStatusCode",
"follow_redirects": "followRedirects",
"headers": "headers",
}
payload = {}
for key, value in kwargs.items():
if key in field_map:
payload[field_map[key]] = value
return self._request("PATCH", f"/monitors/{monitor_id}", json=payload)
def delete_monitor(self, monitor_id: str) -> dict:
"""Delete a monitor."""
return self._request("DELETE", f"/monitors/{monitor_id}")
# ── Checks ────────────────────────────────────────
def list_checks(
self,
monitor_id: str,
limit: int = 50,
offset: int = 0,
) -> dict:
"""List checks for a monitor."""
params = urlencode({"limit": limit, "offset": offset})
return self._request("GET", f"/monitors/{monitor_id}/checks?{params}")
# ── Incidents ─────────────────────────────────────
def list_incidents(
self,
limit: int = 50,
offset: int = 0,
monitor_id: Optional[str] = None,
) -> dict:
"""List incidents for your organization."""
params = {"limit": limit, "offset": offset}
if monitor_id:
params["monitorId"] = monitor_id
query = urlencode(params)
return self._request("GET", f"/incidents?{query}")
def get_incident(self, incident_id: str) -> dict:
"""Get a single incident with its updates."""
return self._request("GET", f"/incidents/{incident_id}")
# ── Alert Channels ────────────────────────────────
def list_alert_channels(self) -> dict:
"""List all alert channels."""
return self._request("GET", "/alert-channels")
def create_alert_channel(
self,
type: str,
name: str,
config: dict,
enabled: bool = True,
) -> dict:
"""Create a new alert channel."""
return self._request(
"POST",
"/alert-channels",
json={
"type": type,
"name": name,
"config": config,
"enabled": enabled,
},
)
def delete_alert_channel(self, channel_id: str) -> dict:
"""Delete an alert channel."""
return self._request("DELETE", f"/alert-channels/{channel_id}")
Usage Examples
Initialize the Client
import os
from sentro import SentroClient
client = SentroClient(os.environ["SENTRO_API_KEY"])
List All Monitors
result = client.list_monitors()
print(f"Total monitors: {result['meta']['total']}")
for monitor in result["data"]:
print(f" {monitor['name']} ({monitor['status']}) - {monitor['url']}")
Create a Monitor
result = client.create_monitor(
name="Production API",
url="https://api.example.com/health",
method="GET",
interval_seconds=60,
timeout_seconds=30,
expected_status_code=200,
headers={"Accept": "application/json"},
)
print(f"Created monitor: {result['data']['id']}")
Get Check History
result = client.list_checks("mon_abc123", limit=100, offset=0)
checks = result["data"]
up_count = sum(1 for c in checks if c["isUp"])
uptime = (up_count / len(checks)) * 100
print(f"Uptime: {uptime:.2f}% over {len(checks)} checks")
print(f"Total checks available: {result['meta']['total']}")
List Recent Incidents
result = client.list_incidents(limit=5)
for incident in result["data"]:
status = "RESOLVED" if incident["resolvedAt"] else "ONGOING"
monitor_name = incident.get("monitor", {}).get("name", "Unknown")
print(f" [{status}] {incident['cause']} ({monitor_name})")
Create a Slack Alert Channel
result = client.create_alert_channel(
type="SLACK",
name="Engineering Alerts",
config={
"webhookUrl": "https://hooks.slack.com/services/T00/B00/xxx",
},
)
print(f"Created alert channel: {result['data']['id']}")
Error Handling
from sentro import SentroClient, SentroError
client = SentroClient(os.environ["SENTRO_API_KEY"])
try:
result = client.get_monitor("non_existent_id")
except SentroError as e:
print(f"Error [{e.status_code}]: {e.message}")
# "Error [404]: Monitor with id 'non_existent_id' not found"
Using Plain Requests
If you prefer not to use a wrapper:
import os
import requests
API_KEY = os.environ["SENTRO_API_KEY"]
BASE_URL = "https://api.sentro.dev/v1"
response = requests.get(
f"{BASE_URL}/monitors",
headers={"Authorization": f"Bearer {API_KEY}"},
)
response.raise_for_status()
data = response.json()
for monitor in data["data"]:
print(f"{monitor['name']} - {monitor['url']}")