Module betterstack.uptime

The betterstack.uptime module provides a Python interface to the BetterStack Uptime API. It converts API endpoints into Python objects with automatic attribute mapping, change tracking, and full CRUD support.

Quick Start

from betterstack.uptime import UptimeAPI
from betterstack.uptime.objects import Monitor, Incident

# Initialize the API client
api = UptimeAPI("your-bearer-token")

# Get all monitors
for monitor in Monitor.get_all_instances(api):
    print(f"{monitor.url}: {monitor.status}")

# Get incidents for a specific monitor
for incident in Incident.filter(api, monitor_id=12345):
    print(f"{incident.started_at}: {incident.cause}")

API Response Format

The BetterStack API returns data in the following format, which is automatically parsed and mapped to object attributes:

{
    "data": {
        "id": "12345",
        "type": "monitor",
        "attributes": {
            "url": "https://example.com",
            "status": "up",
            "check_frequency": 30
        }
    }
}

Submodules

Module Contents

BetterStack Uptime API client library.

This module provides a Python interface for the BetterStack Uptime API.

Example:
>>> from betterstack.uptime import UptimeAPI, Monitor
>>> api = UptimeAPI("your-bearer-token")
>>> monitors = list(Monitor.get_all_instances(api))
>>> for monitor in monitors:
...     print(f"{monitor.pronounceable_name}: {monitor.status}")
class betterstack.uptime.RESTAPI(base_url: str, auth: BearerAuth, retries: int = 3, backoff_factor: float = 0.5, timeout: float = 30.0)[source]

Bases: object

Low-level REST API client with session management and retry logic.

This class handles all HTTP communication with the BetterStack API, including authentication, request retries, and error handling.

Attributes:

base_url: The base URL for all API requests. session: The requests session used for all HTTP calls.

Initialize RESTAPI with session and retry configuration.

Args:

base_url: The URL to be called, must end with a forward slash. auth: Authentication class to be used with requests. retries: Number of retries for failed requests. backoff_factor: Backoff factor for retry delays. timeout: Default timeout for requests in seconds.

Raises:

ValueError: If base_url doesn’t end with a forward slash.

__init__(base_url: str, auth: BearerAuth, retries: int = 3, backoff_factor: float = 0.5, timeout: float = 30.0) None[source]

Initialize RESTAPI with session and retry configuration.

Args:

base_url: The URL to be called, must end with a forward slash. auth: Authentication class to be used with requests. retries: Number of retries for failed requests. backoff_factor: Backoff factor for retry delays. timeout: Default timeout for requests in seconds.

Raises:

ValueError: If base_url doesn’t end with a forward slash.

get(url: str, body: dict[str, Any] | None = None, headers: dict[str, Any] | None = None, parameters: dict[str, Any] | None = None) dict[str, Any][source]

Perform a GET request.

Args:

url: URL path to access (relative to base_url). body: Request body (unused for GET, kept for interface consistency). headers: Additional headers to send. parameters: URL query parameters.

Returns:

Response JSON as a dictionary.

Raises:

APIError: If the request fails.

post(url: str, body: dict[str, Any] | None = None, headers: dict[str, Any] | None = None, parameters: dict[str, Any] | None = None) Response[source]

Perform a POST request.

Args:

url: URL path to access (relative to base_url). body: Request body as a dictionary (will be sent as JSON). headers: Additional headers to send. parameters: URL query parameters.

Returns:

Response object.

Raises:

APIError: If the request fails.

patch(url: str, body: dict[str, Any] | None = None, headers: dict[str, Any] | None = None, parameters: dict[str, Any] | None = None) Response[source]

Perform a PATCH request.

Args:

url: URL path to access (relative to base_url). body: Request body as a dictionary (will be sent as JSON). headers: Additional headers to send. parameters: URL query parameters.

Returns:

Response object.

Raises:

APIError: If the request fails.

delete(url: str, body: dict[str, Any] | None = None, headers: dict[str, Any] | None = None, parameters: dict[str, Any] | None = None) Response[source]

Perform a DELETE request.

Args:

url: URL path to access (relative to base_url). body: Request body (unused for DELETE). headers: Additional headers to send. parameters: URL query parameters.

Returns:

Response object.

Raises:

APIError: If the request fails.

exception betterstack.uptime.APIError(message: str, status_code: int, response_body: dict | None = None)[source]

Bases: BetterStackError

Error returned from the BetterStack API.

__init__(message: str, status_code: int, response_body: dict | None = None) None[source]
exception betterstack.uptime.AuthenticationError(message: str = 'Invalid or missing authentication token')[source]

Bases: APIError

401 Unauthorized - Invalid or missing token.

__init__(message: str = 'Invalid or missing authentication token') None[source]
class betterstack.uptime.BaseAPIObject(id: str, _api: PaginatedAPI, _extras: dict[str, Any]=<factory>, _original_values: dict[str, Any]=<factory>)[source]

Bases: object

Base class for all API objects using dataclasses.

This class provides common functionality for all BetterStack API objects: - Automatic attribute assignment from API responses - Change tracking for efficient updates (only modified fields are sent) - CRUD operations (fetch, save, delete) - Class methods for querying and creating objects

The hybrid approach stores known fields as dataclass fields with proper types, while unknown fields from the API are stored in the _extras dictionary.

Attributes:

id: The unique identifier for this object. _api: Reference to the API client (excluded from repr/compare). _extras: Dictionary for storing unknown API attributes. _original_values: Snapshot of values when object was loaded/saved.

id: str
get_modified_properties() list[str][source]

Return list of modified property names since last save/fetch.

Returns:

List of attribute names that have been modified.

reset_variable_tracking() None[source]

Reset change tracking to current state.

generate_url() str[source]

Create the URL for this specific instance.

Returns:

Full instance URL path.

classmethod generate_global_url() str[source]

Get the collection URL for this object type.

Returns:

Collection URL path.

fetch_data(**kwargs: Any) None[source]

Fetch all attributes from the API.

Args:

**kwargs: Additional parameters for the API request.

save() None[source]

Update all changed attributes on the API.

Only sends modified attributes to minimize API payload.

delete() None[source]

Delete this object from the API.

classmethod get_or_create(api: PaginatedAPI, **kwargs: Any) tuple[bool, Self][source]

Get an existing object or create a new one.

Attempts to find an object matching the given attributes. If no match is found, creates a new object with those attributes.

Args:

api: API instance. **kwargs: Attributes to search for or use when creating.

Returns:

Tuple of (created: bool, object: BaseAPIObject). created is True if a new object was created.

Raises:

ValueError: If multiple objects match the criteria.

classmethod new(api: PaginatedAPI, **kwargs: Any) Self[source]

Create a new object on the API.

Args:

api: API instance. **kwargs: Attributes for the new object.

Returns:

The newly created object.

classmethod filter(api: PaginatedAPI, **kwargs: Any) Generator[Self, None, None][source]

Filter objects using URL query parameters.

Args:

api: API instance with pagination support. **kwargs: Query parameters to filter by.

Yields:

Objects matching the filter criteria.

Raises:

ValidationError: If a filter parameter is not allowed.

classmethod get_all_instances(api: PaginatedAPI) Generator[Self, None, None][source]

Fetch all objects of this type from the API.

Args:

api: API instance with pagination support.

Yields:

All objects of this type.

__init__(id: str, _api: PaginatedAPI, _extras: dict[str, Any]=<factory>, _original_values: dict[str, Any]=<factory>) None
class betterstack.uptime.BearerAuth(token: str)[source]

Bases: AuthBase

Bearer token authentication for requests.

This class implements the requests AuthBase interface to automatically add Bearer token authentication to all requests.

Example:
>>> auth = BearerAuth("your-api-token")
>>> requests.get("https://api.example.com", auth=auth)

Initialize BearerAuth with a token.

Args:

token: The bearer token to use for authentication.

__init__(token: str) None[source]

Initialize BearerAuth with a token.

Args:

token: The bearer token to use for authentication.

exception betterstack.uptime.BetterStackError[source]

Bases: Exception

Base exception for all BetterStack errors.

exception betterstack.uptime.ConfigurationError[source]

Bases: BetterStackError

Configuration error (e.g., missing required settings).

class betterstack.uptime.EscalationPolicy(id: str, _api: PaginatedAPI, _extras: dict[str, Any]=<factory>, _original_values: dict[str, Any]=<factory>, name: str | None = None, repeat_count: int | None = None, repeat_delay: int | None = None, incident_token: str | None = None, policy_group_id: int | None = None, team_name: str | None = None, steps: list[dict[str, Any]] | None=None)[source]

Bases: BaseAPIObject

EscalationPolicy resource from the BetterStack Uptime API.

An escalation policy defines the sequence of notifications sent when an incident occurs. It specifies who to notify and in what order.

Note: This resource uses the v3 API endpoint.

Attributes:

name: The name of the policy. repeat_count: How many times to repeat the escalation steps. repeat_delay: Seconds to wait before each repetition. incident_token: Token for manually reporting incidents. policy_group_id: ID of the policy group. team_name: Name of the team that owns the policy. steps: List of escalation steps.

type: ClassVar[str] = 'policy'
name: str | None = None
repeat_count: int | None = None
repeat_delay: int | None = None
incident_token: str | None = None
policy_group_id: int | None = None
team_name: str | None = None
steps: list[dict[str, Any]] | None = None
__init__(id: str, _api: PaginatedAPI, _extras: dict[str, Any]=<factory>, _original_values: dict[str, Any]=<factory>, name: str | None = None, repeat_count: int | None = None, repeat_delay: int | None = None, incident_token: str | None = None, policy_group_id: int | None = None, team_name: str | None = None, steps: list[dict[str, Any]] | None=None) None
exception betterstack.uptime.ForbiddenError(message: str = 'Access denied')[source]

Bases: APIError

403 Forbidden - Access denied.

__init__(message: str = 'Access denied') None[source]
class betterstack.uptime.Heartbeat(id: str, _api: PaginatedAPI, _extras: dict[str, Any]=<factory>, _original_values: dict[str, Any]=<factory>, name: str | None = None, url: str | None = None, period: int | None = None, grace: int | None = None, call: bool | None = None, sms: bool | None = None, email: bool | None = None, push: bool | None = None, critical_alert: bool | None = None, team_wait: int | None = None, heartbeat_group_id: int | None = None, team_name: str | None = None, sort_index: int | None = None, paused_at: str | None = None, created_at: str | None = None, updated_at: str | None = None, status: str | None = None, maintenance_from: str | None = None, maintenance_to: str | None = None, maintenance_timezone: str | None = None, maintenance_days: list[str] | None = None, policy_id: int | None = None)[source]

Bases: BaseAPIObject

Heartbeat resource from the BetterStack Uptime API.

A heartbeat monitor expects regular “heartbeat” pings from your application. If a ping is not received within the expected period, an incident is triggered.

Attributes:

name: The name of the heartbeat. url: The unique URL to ping for this heartbeat. period: Expected time between heartbeats in seconds. grace: Grace period in seconds before triggering an incident. call: Whether to make phone calls on incidents. sms: Whether to send SMS on incidents. email: Whether to send emails on incidents. push: Whether to send push notifications on incidents. critical_alert: Whether to send as a critical/high-urgency alert. team_wait: Seconds to wait before escalating to the team. heartbeat_group_id: ID of the heartbeat group this belongs to. team_name: The team that owns this heartbeat (for filtering). sort_index: Sort order for the heartbeat in the dashboard. paused_at: When the heartbeat was paused (ISO 8601), if paused. created_at: When the heartbeat was created (ISO 8601 format). updated_at: When the heartbeat was last updated (ISO 8601 format). status: Current status of the heartbeat (e.g., “up”, “down”, “paused”). maintenance_from: Start time of the maintenance window (HH:MM:SS format). maintenance_to: End time of the maintenance window (HH:MM:SS format). maintenance_timezone: Timezone for the maintenance window. maintenance_days: List of days for maintenance (e.g., [“mon”, “tue”]). policy_id: ID of the escalation policy for this heartbeat.

type: ClassVar[str] = 'heartbeat'
name: str | None = None
url: str | None = None
period: int | None = None
grace: int | None = None
call: bool | None = None
sms: bool | None = None
email: bool | None = None
push: bool | None = None
critical_alert: bool | None = None
team_wait: int | None = None
heartbeat_group_id: int | None = None
team_name: str | None = None
sort_index: int | None = None
paused_at: str | None = None
created_at: str | None = None
updated_at: str | None = None
status: str | None = None
maintenance_from: str | None = None
maintenance_to: str | None = None
maintenance_timezone: str | None = None
maintenance_days: list[str] | None = None
policy_id: int | None = None
property is_paused: bool

Check if the heartbeat is currently paused.

Returns:

True if the heartbeat has a paused_at timestamp.

__init__(id: str, _api: PaginatedAPI, _extras: dict[str, Any]=<factory>, _original_values: dict[str, Any]=<factory>, name: str | None = None, url: str | None = None, period: int | None = None, grace: int | None = None, call: bool | None = None, sms: bool | None = None, email: bool | None = None, push: bool | None = None, critical_alert: bool | None = None, team_wait: int | None = None, heartbeat_group_id: int | None = None, team_name: str | None = None, sort_index: int | None = None, paused_at: str | None = None, created_at: str | None = None, updated_at: str | None = None, status: str | None = None, maintenance_from: str | None = None, maintenance_to: str | None = None, maintenance_timezone: str | None = None, maintenance_days: list[str] | None = None, policy_id: int | None = None) None
class betterstack.uptime.HeartbeatGroup(id: str, _api: PaginatedAPI, _extras: dict[str, Any]=<factory>, _original_values: dict[str, Any]=<factory>, name: str | None = None, sort_index: int | None = None, created_at: str | None = None, updated_at: str | None = None, paused: bool | None = None, team_name: str | None = None, _heartbeats: list[Heartbeat] | None = None)[source]

Bases: BaseAPIObject

Heartbeat Group resource from the BetterStack Uptime API.

A heartbeat group is a collection of heartbeat monitors that can be managed together. Groups help organize heartbeats logically and can be paused/resumed as a unit.

Attributes:

name: The name of the heartbeat group. sort_index: Sort order for the group in the dashboard. created_at: When the group was created (ISO 8601 format). updated_at: When the group was last updated (ISO 8601 format). paused: Whether all heartbeats in the group are paused. team_name: The team that owns this heartbeat group (for filtering).

type: ClassVar[str] = 'heartbeat_group'
name: str | None = None
sort_index: int | None = None
created_at: str | None = None
updated_at: str | None = None
paused: bool | None = None
team_name: str | None = None
property heartbeats: list[Heartbeat]

Get heartbeats in this group, fetching if necessary.

Returns:

List of Heartbeat objects in this group.

fetch_heartbeats() None[source]

Fetch all heartbeats belonging to this group.

__init__(id: str, _api: PaginatedAPI, _extras: dict[str, Any]=<factory>, _original_values: dict[str, Any]=<factory>, name: str | None = None, sort_index: int | None = None, created_at: str | None = None, updated_at: str | None = None, paused: bool | None = None, team_name: str | None = None, _heartbeats: list[Heartbeat] | None = None) None
class betterstack.uptime.Incident(id: str, _api: PaginatedAPI, _extras: dict[str, Any]=<factory>, _original_values: dict[str, Any]=<factory>, name: str | None = None, url: str | None = None, http_method: str | None = None, cause: str | None = None, incident_group_id: int | None = None, started_at: str | None = None, acknowledged_at: str | None = None, acknowledged_by: str | None = None, resolved_at: str | None = None, resolved_by: str | None = None, status: str | None = None, team_name: str | None = None, response_content: str | None = None, response_url: str | None = None, response_options: dict[str, Any] | None=None, regions: list[str] | None = None, screenshot_url: str | None = None, origin_url: str | None = None, escalation_policy_id: int | None = None, ssl_certificate_expires_at: str | None = None, domain_expires_at: str | None = None, call: bool | None = None, sms: bool | None = None, email: bool | None = None, push: bool | None = None, critical_alert: bool | None = None, metadata: dict[str, Any] | None=None, monitor_id: int | None = None, heartbeat_id: int | None = None)[source]

Bases: BaseAPIObject

Incident resource from the BetterStack Uptime API (v3).

An incident represents a period of downtime or issues detected by a monitor or heartbeat. Incidents are automatically created when a monitor or heartbeat fails and can be acknowledged and resolved manually or automatically.

Note:

This resource uses the v3 API endpoint (/api/v3/incidents).

Attributes:

name: The name/title of the incident. url: The URL that triggered the incident (for URL monitors). http_method: The HTTP method used when the incident was detected. cause: The cause of the incident (e.g., “Keyword not found”). incident_group_id: ID of the incident group this incident belongs to. started_at: When the incident started (ISO 8601 format). acknowledged_at: When the incident was acknowledged (ISO 8601 format). acknowledged_by: Name of who acknowledged the incident. resolved_at: When the incident was resolved (ISO 8601 format). resolved_by: Name of who resolved the incident. status: Current status of the incident (e.g., “Started”, “Resolved”). team_name: The team that owns this incident (for filtering). response_content: The response body content when the incident occurred. response_url: The final URL after any redirects. response_options: Additional response information/options. regions: List of regions where the incident was detected. screenshot_url: URL to a screenshot taken during the incident. origin_url: The original URL before any redirects. escalation_policy_id: ID of the escalation policy that was triggered. ssl_certificate_expires_at: When the SSL certificate expires. domain_expires_at: When the domain expires. call: Whether phone calls were made for this incident. sms: Whether SMS was sent for this incident. email: Whether email was sent for this incident. push: Whether push notifications were sent for this incident. critical_alert: Whether critical/high-urgency alerts were sent. metadata: Custom metadata dictionary attached to this incident. monitor_id: ID of the monitor that triggered this incident. heartbeat_id: ID of the heartbeat that triggered this incident.

type: ClassVar[str] = 'incident'
name: str | None = None
url: str | None = None
http_method: str | None = None
cause: str | None = None
incident_group_id: int | None = None
started_at: str | None = None
acknowledged_at: str | None = None
acknowledged_by: str | None = None
resolved_at: str | None = None
resolved_by: str | None = None
status: str | None = None
team_name: str | None = None
response_content: str | None = None
response_url: str | None = None
response_options: dict[str, Any] | None = None
regions: list[str] | None = None
screenshot_url: str | None = None
origin_url: str | None = None
escalation_policy_id: int | None = None
ssl_certificate_expires_at: str | None = None
domain_expires_at: str | None = None
call: bool | None = None
sms: bool | None = None
email: bool | None = None
push: bool | None = None
critical_alert: bool | None = None
metadata: dict[str, Any] | None = None
monitor_id: int | None = None
heartbeat_id: int | None = None
property is_resolved: bool

Check if the incident has been resolved.

Returns:

True if the incident has a resolved_at timestamp or status is “Resolved”.

property is_acknowledged: bool

Check if the incident has been acknowledged.

Returns:

True if the incident has an acknowledged_at timestamp or status is “Acknowledged”.

acknowledge(acknowledged_by: str | None = None) None[source]

Acknowledge this incident.

Acknowledging an incident indicates that someone is aware of the issue and is working on it. This stops further escalations.

Args:
acknowledged_by: Optional name of who is acknowledging

the incident.

resolve(resolved_by: str | None = None) None[source]

Resolve this incident.

Resolving an incident marks it as fixed. This stops all notifications and escalations for this incident.

Args:

resolved_by: Optional name of who is resolving the incident.

__init__(id: str, _api: PaginatedAPI, _extras: dict[str, Any]=<factory>, _original_values: dict[str, Any]=<factory>, name: str | None = None, url: str | None = None, http_method: str | None = None, cause: str | None = None, incident_group_id: int | None = None, started_at: str | None = None, acknowledged_at: str | None = None, acknowledged_by: str | None = None, resolved_at: str | None = None, resolved_by: str | None = None, status: str | None = None, team_name: str | None = None, response_content: str | None = None, response_url: str | None = None, response_options: dict[str, Any] | None=None, regions: list[str] | None = None, screenshot_url: str | None = None, origin_url: str | None = None, escalation_policy_id: int | None = None, ssl_certificate_expires_at: str | None = None, domain_expires_at: str | None = None, call: bool | None = None, sms: bool | None = None, email: bool | None = None, push: bool | None = None, critical_alert: bool | None = None, metadata: dict[str, Any] | None=None, monitor_id: int | None = None, heartbeat_id: int | None = None) None
class betterstack.uptime.Monitor(id: str, _api: PaginatedAPI, _extras: dict[str, Any]=<factory>, _original_values: dict[str, Any]=<factory>, url: str | None = None, pronounceable_name: str | None = None, monitor_type: str | None = None, monitor_group_id: int | None = None, last_checked_at: str | None = None, status: str | None = None, policy_id: int | None = None, expiration_policy_id: int | None = None, team_name: str | None = None, required_keyword: str | None = None, verify_ssl: bool | None = None, check_frequency: int | None = None, call: bool | None = None, sms: bool | None = None, email: bool | None = None, push: bool | None = None, critical_alert: bool | None = None, team_wait: int | None = None, http_method: str | None = None, request_timeout: int | None = None, recovery_period: int | None = None, request_headers: list[dict[str, str]] | None=None, request_body: str | None = None, paused_at: str | None = None, created_at: str | None = None, updated_at: str | None = None, ssl_expiration: int | None = None, domain_expiration: int | None = None, regions: list[str] | None = None, port: str | None = None, confirmation_period: int | None = None, expected_status_codes: list[int] | None = None, maintenance_days: list[str] | None = None, maintenance_from: str | None = None, maintenance_to: str | None = None, maintenance_timezone: str | None = None, playwright_script: str | None = None, environment_variables: dict[str, Any] | None=None, auth_username: str | None = None, auth_password: str | None = None, follow_redirects: bool | None = None, remember_cookies: bool | None = None, _sla: MonitorSLA | None = None)[source]

Bases: BaseAPIObject

Monitor resource from the BetterStack Uptime API.

A monitor represents a URL or service that is being monitored for uptime. Monitors can check HTTP endpoints, ping hosts, test TCP/UDP ports, and more.

Attributes:

url: The URL of your website or the host you want to ping. pronounceable_name: Human-readable name used in phone call alerts. monitor_type: Type of monitor (e.g., ‘status’, ‘keyword’, ‘ping’, ‘tcp’). monitor_group_id: ID of the monitor group this monitor belongs to. last_checked_at: When the monitor was last checked (ISO 8601 datetime). status: Current status (e.g., ‘up’, ‘down’, ‘paused’, ‘maintenance’). policy_id: The escalation policy ID for this monitor. expiration_policy_id: The expiration escalation policy ID. team_name: The team this monitor is in. required_keyword: Keyword that must be present (for keyword/udp monitors). verify_ssl: Whether to verify SSL certificate validity. check_frequency: How often to check, in seconds. call: Whether to call the on-call person on incidents. sms: Whether to send SMS on incidents. email: Whether to send email on incidents. push: Whether to send push notifications on incidents. critical_alert: Whether to send critical alert push notifications. team_wait: Seconds to wait before escalating to the team. http_method: HTTP method for requests (e.g., ‘GET’, ‘POST’). request_timeout: Request timeout in seconds (or ms for server monitors). recovery_period: Seconds before marking incident as resolved after recovery. request_headers: Array of custom HTTP headers with ‘name’ and ‘value’ properties. request_body: Request body for POST/PUT/PATCH, or domain for DNS monitors. paused_at: When the monitor was paused (ISO 8601 datetime), null if not paused. created_at: When the monitor was created (ISO 8601 datetime). updated_at: When the monitor was last updated (ISO 8601 datetime). ssl_expiration: Days before SSL expiration to alert. domain_expiration: Days before domain expiration to alert. regions: Array of regions to check from (e.g., ‘us’, ‘eu’, ‘as’, ‘au’). port: Port for TCP/UDP/SMTP/POP/IMAP monitors. confirmation_period: Seconds to wait after failure before starting incident. expected_status_codes: Array of acceptable HTTP status codes. maintenance_days: Array of maintenance days (e.g., ‘mon’, ‘tue’, ‘wed’). maintenance_from: Start of daily maintenance window (e.g., ‘01:00:00’). maintenance_to: End of daily maintenance window (e.g., ‘03:00:00’). maintenance_timezone: Timezone for maintenance window. playwright_script: JavaScript source code for Playwright monitors. environment_variables: Environment variables for Playwright scenarios. auth_username: Basic auth username. auth_password: Basic auth password. follow_redirects: Whether to follow HTTP redirects. remember_cookies: Whether to remember cookies between checks.

type: ClassVar[str] = 'monitor'
url: str | None = None
pronounceable_name: str | None = None
monitor_type: str | None = None
monitor_group_id: int | None = None
last_checked_at: str | None = None
status: str | None = None
policy_id: int | None = None
expiration_policy_id: int | None = None
team_name: str | None = None
required_keyword: str | None = None
verify_ssl: bool | None = None
check_frequency: int | None = None
call: bool | None = None
sms: bool | None = None
email: bool | None = None
push: bool | None = None
critical_alert: bool | None = None
team_wait: int | None = None
http_method: str | None = None
request_timeout: int | None = None
recovery_period: int | None = None
request_headers: list[dict[str, str]] | None = None
request_body: str | None = None
paused_at: str | None = None
created_at: str | None = None
updated_at: str | None = None
ssl_expiration: int | None = None
domain_expiration: int | None = None
regions: list[str] | None = None
port: str | None = None
confirmation_period: int | None = None
expected_status_codes: list[int] | None = None
maintenance_days: list[str] | None = None
maintenance_from: str | None = None
maintenance_to: str | None = None
maintenance_timezone: str | None = None
playwright_script: str | None = None
environment_variables: dict[str, Any] | None = None
auth_username: str | None = None
auth_password: str | None = None
follow_redirects: bool | None = None
remember_cookies: bool | None = None
property sla: MonitorSLA

Get or create the SLA object for this monitor.

Returns:

MonitorSLA object for this monitor.

property is_paused: bool

Check if the monitor is currently paused.

Returns:

True if the monitor is paused, False otherwise.

__init__(id: str, _api: PaginatedAPI, _extras: dict[str, Any]=<factory>, _original_values: dict[str, Any]=<factory>, url: str | None = None, pronounceable_name: str | None = None, monitor_type: str | None = None, monitor_group_id: int | None = None, last_checked_at: str | None = None, status: str | None = None, policy_id: int | None = None, expiration_policy_id: int | None = None, team_name: str | None = None, required_keyword: str | None = None, verify_ssl: bool | None = None, check_frequency: int | None = None, call: bool | None = None, sms: bool | None = None, email: bool | None = None, push: bool | None = None, critical_alert: bool | None = None, team_wait: int | None = None, http_method: str | None = None, request_timeout: int | None = None, recovery_period: int | None = None, request_headers: list[dict[str, str]] | None=None, request_body: str | None = None, paused_at: str | None = None, created_at: str | None = None, updated_at: str | None = None, ssl_expiration: int | None = None, domain_expiration: int | None = None, regions: list[str] | None = None, port: str | None = None, confirmation_period: int | None = None, expected_status_codes: list[int] | None = None, maintenance_days: list[str] | None = None, maintenance_from: str | None = None, maintenance_to: str | None = None, maintenance_timezone: str | None = None, playwright_script: str | None = None, environment_variables: dict[str, Any] | None=None, auth_username: str | None = None, auth_password: str | None = None, follow_redirects: bool | None = None, remember_cookies: bool | None = None, _sla: MonitorSLA | None = None) None
class betterstack.uptime.MonitorGroup(id: str, _api: PaginatedAPI, _extras: dict[str, Any]=<factory>, _original_values: dict[str, Any]=<factory>, name: str | None = None, sort_index: int | None = None, created_at: str | None = None, updated_at: str | None = None, paused: bool | None = None, team_name: str | None = None, _monitors: list[Monitor] | None = None)[source]

Bases: BaseAPIObject

Monitor Group resource from the BetterStack Uptime API.

A monitor group is a collection of monitors that can be managed together. Groups help organize monitors logically and can be paused/resumed as a unit.

Attributes:

name: The name of the monitor group. sort_index: Sort order for the group in the dashboard. created_at: When the group was created (ISO 8601 format). updated_at: When the group was last updated (ISO 8601 format). paused: Whether all monitors in the group are paused. team_name: The team that owns this monitor group (for filtering).

type: ClassVar[str] = 'monitor_group'
name: str | None = None
sort_index: int | None = None
created_at: str | None = None
updated_at: str | None = None
paused: bool | None = None
team_name: str | None = None
property monitors: list[Monitor]

Get monitors in this group, fetching if necessary.

Returns:

List of Monitor objects in this group.

fetch_monitors() None[source]

Fetch all monitors belonging to this group.

__init__(id: str, _api: PaginatedAPI, _extras: dict[str, Any]=<factory>, _original_values: dict[str, Any]=<factory>, name: str | None = None, sort_index: int | None = None, created_at: str | None = None, updated_at: str | None = None, paused: bool | None = None, team_name: str | None = None, _monitors: list[Monitor] | None = None) None
class betterstack.uptime.MonitorSLA(id: str, _api: PaginatedAPI, _extras: dict[str, Any]=<factory>, _original_values: dict[str, Any]=<factory>, availability: float | None = None, downtime_duration: int | None = None, number_of_incidents: int | None = None, longest_incident: int | None = None, average_incident: int | None = None, _sla_start: str | None = None, _sla_end: str | None = None)[source]

Bases: BaseAPIObject

Monitor SLA (Service Level Agreement) data.

This object provides SLA statistics for a specific monitor over a given time period.

Attributes:

availability: Availability percentage (0-100). downtime_duration: Total downtime in seconds. number_of_incidents: Number of incidents in the period. longest_incident: Duration of longest incident in seconds. average_incident: Average incident duration in seconds.

type: ClassVar[str] = 'monitor_sla'
availability: float | None = None
downtime_duration: int | None = None
number_of_incidents: int | None = None
longest_incident: int | None = None
average_incident: int | None = None
generate_url() str[source]

Create the URL for this SLA endpoint.

Returns:

Full SLA URL path.

classmethod generate_global_url() str[source]

SLA objects don’t have a global URL.

Raises:

ValueError: Always, as SLA has no collection endpoint.

property timeframe: tuple[str | None, str | None]

Get the current SLA timeframe.

Returns:

Tuple of (start_date, end_date).

__init__(id: str, _api: PaginatedAPI, _extras: dict[str, Any]=<factory>, _original_values: dict[str, Any]=<factory>, availability: float | None = None, downtime_duration: int | None = None, number_of_incidents: int | None = None, longest_incident: int | None = None, average_incident: int | None = None, _sla_start: str | None = None, _sla_end: str | None = None) None
fetch_sla(from_date: str, to_date: str) None[source]

Fetch SLA data for a specific time period.

Args:

from_date: Start date in ISO 8601 format. to_date: End date in ISO 8601 format.

exception betterstack.uptime.NotFoundError(message: str = 'Resource not found')[source]

Bases: APIError

404 Not Found - Resource doesn’t exist.

__init__(message: str = 'Resource not found') None[source]
class betterstack.uptime.OnCallCalendar(id: str, _api: PaginatedAPI, _extras: dict[str, Any]=<factory>, _original_values: dict[str, Any]=<factory>, name: str | None = None, default_calendar: bool | None = None, team_name: str | None = None, _on_call_users: list[dict[str, Any]] | None=None, _events: list[OnCallEvent] | None = None)[source]

Bases: BaseAPIObject

OnCallCalendar resource from the BetterStack Uptime API.

An on-call calendar (schedule) defines who is on-call and when. It manages on-call rotations and events for incident response.

Attributes:

name: The name of the schedule. default_calendar: Whether this is the default calendar for the team. team_name: Name of the team associated with the schedule.

type: ClassVar[str] = 'on_call_calendar'
name: str | None = None
default_calendar: bool | None = None
team_name: str | None = None
property on_call_users: list[dict[str, Any]]

Get the current on-call users for this calendar.

Returns:

List of user data dictionaries.

property events: list[OnCallEvent]

Get the events for this on-call calendar (lazy-loaded).

Returns:

List of OnCallEvent objects.

fetch_events() list[OnCallEvent][source]

Fetch all events for this on-call calendar from the API.

Returns:

List of OnCallEvent objects.

create_rotation(users: list[str], rotation_length: int, rotation_period: str, start_rotations_at: str, end_rotations_at: str) dict[str, Any][source]

Create an on-call rotation for this calendar.

Args:

users: List of email addresses of users to include. rotation_length: Length of the rotation period. rotation_period: Period type (‘hour’, ‘day’, ‘week’). start_rotations_at: Start time in ISO 8601 format. end_rotations_at: End time in ISO 8601 format.

Returns:

API response data for the created rotation.

__init__(id: str, _api: PaginatedAPI, _extras: dict[str, Any]=<factory>, _original_values: dict[str, Any]=<factory>, name: str | None = None, default_calendar: bool | None = None, team_name: str | None = None, _on_call_users: list[dict[str, Any]] | None=None, _events: list[OnCallEvent] | None = None) None
class betterstack.uptime.OnCallEvent(id: str, _api: PaginatedAPI, _extras: dict[str, Any]=<factory>, _original_values: dict[str, Any]=<factory>, starts_at: str | None = None, ends_at: str | None = None, users: list[str] | None = None, override: bool | None = None, _calendar_id: str | None = None)[source]

Bases: BaseAPIObject

OnCallEvent resource from the BetterStack Uptime API.

An on-call event represents a time period when specific users are on-call.

Attributes:

starts_at: Start time of the event in ISO 8601 format. ends_at: End time of the event in ISO 8601 format. users: List of email addresses of users on-call during this event. override: Whether this is an override event.

type: ClassVar[str] = 'on_call_event'
starts_at: str | None = None
ends_at: str | None = None
users: list[str] | None = None
override: bool | None = None
generate_url() str[source]

Create the URL for this event endpoint.

Returns:

Full event URL path.

Raises:

ValueError: If calendar_id is not set.

classmethod generate_global_url() str[source]

Events don’t have a global URL without a calendar ID.

Raises:

ValueError: Always, as events require a calendar ID.

__init__(id: str, _api: PaginatedAPI, _extras: dict[str, Any]=<factory>, _original_values: dict[str, Any]=<factory>, starts_at: str | None = None, ends_at: str | None = None, users: list[str] | None = None, override: bool | None = None, _calendar_id: str | None = None) None
class betterstack.uptime.PaginatedAPI(base_url: str, auth: BearerAuth, retries: int = 3, backoff_factor: float = 0.5, timeout: float = 30.0, max_workers: int = 5)[source]

Bases: RESTAPI

REST API client that handles paginated responses.

This class extends RESTAPI to automatically follow pagination links and yield all results across multiple pages. Supports concurrent fetching of pages for improved performance.

Attributes:

max_workers: Maximum number of threads for concurrent page fetching.

Initialize PaginatedAPI with threading configuration.

Args:

base_url: The URL to be called, must end with a forward slash. auth: Authentication class to be used with requests. retries: Number of retries for failed requests. backoff_factor: Backoff factor for retry delays. timeout: Default timeout for requests in seconds. max_workers: Maximum number of threads for concurrent page fetching.

__init__(base_url: str, auth: BearerAuth, retries: int = 3, backoff_factor: float = 0.5, timeout: float = 30.0, max_workers: int = 5) None[source]

Initialize PaginatedAPI with threading configuration.

Args:

base_url: The URL to be called, must end with a forward slash. auth: Authentication class to be used with requests. retries: Number of retries for failed requests. backoff_factor: Backoff factor for retry delays. timeout: Default timeout for requests in seconds. max_workers: Maximum number of threads for concurrent page fetching.

get(url: str, body: dict[str, Any] | None = None, headers: dict[str, Any] | None = None, parameters: dict[str, Any] | None = None) Generator[dict[str, Any], None, None][source]

Perform a GET request with automatic pagination and concurrent fetching.

This method fetches the first page to determine total pages, then fetches remaining pages concurrently using a thread pool. Results are yielded in page order.

Args:

url: URL path to access (relative to base_url). body: Request body (unused for GET). headers: Additional headers to send. parameters: URL query parameters.

Yields:

Individual items from the response data array.

class betterstack.uptime.PolicyStep(step_type: str = 'escalation', wait_before: int = 0, urgency_id: int | None = None, step_members: list[dict[str, str]] | None = None, timezone: str | None = None, days: list[str] | None = None, time_from: str | None = None, time_to: str | None = None, policy_id: int | None = None, policy_metadata_key: str | None = None)[source]

Bases: object

Represents a single step in an escalation policy.

This is a helper class for constructing escalation policy steps. It is not a full API object but can be used when creating policies.

Attributes:

step_type: Type of step (‘escalation’ or ‘time_branching’). wait_before: Seconds to wait before executing this step. urgency_id: ID of the urgency level for this step. step_members: List of members to notify. timezone: Timezone for time branching steps. days: Days of the week for time branching. time_from: Start time for time branching. time_to: End time for time branching. policy_id: ID of the policy to branch to. policy_metadata_key: Metadata key for the branched policy.

step_type: str = 'escalation'
wait_before: int = 0
urgency_id: int | None = None
step_members: list[dict[str, str]] | None = None
timezone: str | None = None
days: list[str] | None = None
time_from: str | None = None
time_to: str | None = None
policy_id: int | None = None
policy_metadata_key: str | None = None
to_dict() dict[str, Any][source]

Convert step to dictionary for API requests.

Returns:

Dictionary representation of the step.

__init__(step_type: str = 'escalation', wait_before: int = 0, urgency_id: int | None = None, step_members: list[dict[str, str]] | None = None, timezone: str | None = None, days: list[str] | None = None, time_from: str | None = None, time_to: str | None = None, policy_id: int | None = None, policy_metadata_key: str | None = None) None
exception betterstack.uptime.RateLimitError(message: str = 'Rate limit exceeded', retry_after: int | None = None)[source]

Bases: APIError

429 Too Many Requests - Rate limit exceeded.

__init__(message: str = 'Rate limit exceeded', retry_after: int | None = None) None[source]
exception betterstack.uptime.ServerError(message: str = 'Server error', status_code: int = 500)[source]

Bases: APIError

5xx Server Error - Server-side issue.

__init__(message: str = 'Server error', status_code: int = 500) None[source]
class betterstack.uptime.StatusPage(id: str, _api: PaginatedAPI, _extras: dict[str, Any]=<factory>, _original_values: dict[str, Any]=<factory>, company_name: str | None = None, company_url: str | None = None, contact_url: str | None = None, logo_url: str | None = None, timezone: str | None = None, subdomain: str | None = None, custom_domain: str | None = None, custom_css: str | None = None, custom_javascript: str | None = None, google_analytics_id: str | None = None, min_incident_length: int | None = None, announcement: str | None = None, announcement_embed_visible: bool | None = None, announcement_embed_css: str | None = None, announcement_embed_link: str | None = None, automatic_reports: bool | None = None, status_page_group_id: int | None = None, subscribable: bool | None = None, hide_from_search_engines: bool | None = None, password_enabled: bool | None = None, ip_allowlist: list[str] | None = None, history: int | None = None, aggregate_state: str | None = None, design: str | None = None, navigation_links: list[dict[str, str]] | None=None, theme: str | None = None, layout: str | None = None, created_at: str | None = None, updated_at: str | None = None, _sections: list[StatusPageSection] | None = None, _resources: list[StatusPageResource] | None = None)[source]

Bases: BaseAPIObject

StatusPage resource from the BetterStack Uptime API.

A status page displays the current operational status of your services and provides a public-facing view for your users.

Attributes:

company_name: The name of the company. company_url: The URL of the company website. contact_url: URL for emergency contact. logo_url: URL of the company logo. timezone: Timezone for the status page. subdomain: Subdomain for the status page (e.g., ‘my-company’). custom_domain: Custom domain for the status page. custom_css: Custom CSS for the status page. custom_javascript: Custom JavaScript for the status page. google_analytics_id: Google Analytics ID for tracking. min_incident_length: Minimum incident length in seconds to display. announcement: Announcement text to display. announcement_embed_visible: Whether the announcement embed is visible. announcement_embed_css: Custom CSS for the announcement embed. announcement_embed_link: Link for the announcement embed. automatic_reports: Whether automatic reports are enabled. status_page_group_id: ID of the status page group. subscribable: Whether users can subscribe to updates. hide_from_search_engines: Whether to hide from search engines. password_enabled: Whether password protection is enabled. ip_allowlist: List of allowed IP addresses or CIDR ranges. history: Number of days to display on the status page. aggregate_state: Current aggregate operational state. design: Design version (‘v1’ or ‘v2’). navigation_links: Navigation links for the status page. theme: Theme of the status page (‘light’, ‘dark’, ‘system’). layout: Layout of the status page (‘vertical’, ‘horizontal’). created_at: When the status page was created. updated_at: When the status page was last updated.

type: ClassVar[str] = 'status_page'
company_name: str | None = None
company_url: str | None = None
contact_url: str | None = None
logo_url: str | None = None
timezone: str | None = None
subdomain: str | None = None
custom_domain: str | None = None
custom_css: str | None = None
custom_javascript: str | None = None
google_analytics_id: str | None = None
min_incident_length: int | None = None
announcement: str | None = None
announcement_embed_visible: bool | None = None
announcement_embed_css: str | None = None
automatic_reports: bool | None = None
status_page_group_id: int | None = None
subscribable: bool | None = None
hide_from_search_engines: bool | None = None
password_enabled: bool | None = None
ip_allowlist: list[str] | None = None
history: int | None = None
aggregate_state: str | None = None
design: str | None = None
theme: str | None = None
layout: str | None = None
created_at: str | None = None
updated_at: str | None = None
property sections: list[StatusPageSection]

Get the sections for this status page (lazy-loaded).

Returns:

List of StatusPageSection objects.

property resources: list[StatusPageResource]

Get the resources for this status page (lazy-loaded).

Returns:

List of StatusPageResource objects.

fetch_sections() list[StatusPageSection][source]

Fetch all sections for this status page from the API.

Returns:

List of StatusPageSection objects.

fetch_resources() list[StatusPageResource][source]

Fetch all resources for this status page from the API.

Returns:

List of StatusPageResource objects.

__init__(id: str, _api: PaginatedAPI, _extras: dict[str, Any]=<factory>, _original_values: dict[str, Any]=<factory>, company_name: str | None = None, company_url: str | None = None, contact_url: str | None = None, logo_url: str | None = None, timezone: str | None = None, subdomain: str | None = None, custom_domain: str | None = None, custom_css: str | None = None, custom_javascript: str | None = None, google_analytics_id: str | None = None, min_incident_length: int | None = None, announcement: str | None = None, announcement_embed_visible: bool | None = None, announcement_embed_css: str | None = None, announcement_embed_link: str | None = None, automatic_reports: bool | None = None, status_page_group_id: int | None = None, subscribable: bool | None = None, hide_from_search_engines: bool | None = None, password_enabled: bool | None = None, ip_allowlist: list[str] | None = None, history: int | None = None, aggregate_state: str | None = None, design: str | None = None, navigation_links: list[dict[str, str]] | None=None, theme: str | None = None, layout: str | None = None, created_at: str | None = None, updated_at: str | None = None, _sections: list[StatusPageSection] | None = None, _resources: list[StatusPageResource] | None = None) None
class betterstack.uptime.StatusPageGroup(id: str, _api: PaginatedAPI, _extras: dict[str, Any]=<factory>, _original_values: dict[str, Any]=<factory>, name: str | None = None, sort_index: int | None = None, created_at: str | None = None, updated_at: str | None = None)[source]

Bases: BaseAPIObject

StatusPageGroup resource from the BetterStack Uptime API.

A status page group is used to organize multiple status pages.

Attributes:

name: The name of the group. sort_index: Sorting index for the group. created_at: When the group was created. updated_at: When the group was last updated.

type: ClassVar[str] = 'status_page_group'
name: str | None = None
sort_index: int | None = None
created_at: str | None = None
updated_at: str | None = None
__init__(id: str, _api: PaginatedAPI, _extras: dict[str, Any]=<factory>, _original_values: dict[str, Any]=<factory>, name: str | None = None, sort_index: int | None = None, created_at: str | None = None, updated_at: str | None = None) None
class betterstack.uptime.StatusPageResource(id: str, _api: PaginatedAPI, _extras: dict[str, Any]=<factory>, _original_values: dict[str, Any]=<factory>, status_page_section_id: int | None = None, resource_id: int | None = None, resource_type: str | None = None, history: bool | None = None, widget_type: str | None = None, public_name: str | None = None, explanation: str | None = None, position: int | None = None, fixed_position: bool | None = None, availability: float | None = None, status: str | None = None, status_history: list[dict[str, Any]] | None=None, _status_page_id: str | None = None)[source]

Bases: BaseAPIObject

StatusPageResource resource from the BetterStack Uptime API.

A resource represents a monitor, heartbeat, or other item displayed on a status page.

Attributes:

status_page_section_id: ID of the section containing this resource. resource_id: ID of the underlying resource (monitor, heartbeat, etc.). resource_type: Type of the resource (‘Monitor’, ‘Heartbeat’, etc.). history: Whether to show history for this resource. widget_type: Widget type (‘plain’, ‘history’, ‘response_times’, ‘chart_only’). public_name: Public name displayed on the status page. explanation: Help text for the resource. position: Position of the resource on the status page. fixed_position: Whether position reorders are prevented. availability: Availability percentage of the resource. status: Current operational status. status_history: Historical status data.

type: ClassVar[str] = 'status_page_resource'
status_page_section_id: int | None = None
resource_id: int | None = None
resource_type: str | None = None
history: bool | None = None
widget_type: str | None = None
public_name: str | None = None
explanation: str | None = None
position: int | None = None
fixed_position: bool | None = None
availability: float | None = None
status: str | None = None
status_history: list[dict[str, Any]] | None = None
generate_url() str[source]

Create the URL for this resource endpoint.

Returns:

Full resource URL path.

Raises:

ValueError: If status_page_id is not set.

classmethod generate_global_url() str[source]

Resources don’t have a global URL without a status page ID.

Raises:

ValueError: Always, as resources require a status page ID.

__init__(id: str, _api: PaginatedAPI, _extras: dict[str, Any]=<factory>, _original_values: dict[str, Any]=<factory>, status_page_section_id: int | None = None, resource_id: int | None = None, resource_type: str | None = None, history: bool | None = None, widget_type: str | None = None, public_name: str | None = None, explanation: str | None = None, position: int | None = None, fixed_position: bool | None = None, availability: float | None = None, status: str | None = None, status_history: list[dict[str, Any]] | None=None, _status_page_id: str | None = None) None
class betterstack.uptime.StatusPageSection(id: str, _api: PaginatedAPI, _extras: dict[str, Any]=<factory>, _original_values: dict[str, Any]=<factory>, name: str | None = None, position: int | None = None, created_at: str | None = None, updated_at: str | None = None, _status_page_id: str | None = None)[source]

Bases: BaseAPIObject

StatusPageSection resource from the BetterStack Uptime API.

A section is a grouping of resources on a status page.

Attributes:

name: The name of the section. position: The position of the section on the status page. created_at: When the section was created. updated_at: When the section was last updated.

type: ClassVar[str] = 'status_page_section'
name: str | None = None
position: int | None = None
created_at: str | None = None
updated_at: str | None = None
generate_url() str[source]

Create the URL for this section endpoint.

Returns:

Full section URL path.

Raises:

ValueError: If status_page_id is not set.

classmethod generate_global_url() str[source]

Sections don’t have a global URL without a status page ID.

Raises:

ValueError: Always, as sections require a status page ID.

__init__(id: str, _api: PaginatedAPI, _extras: dict[str, Any]=<factory>, _original_values: dict[str, Any]=<factory>, name: str | None = None, position: int | None = None, created_at: str | None = None, updated_at: str | None = None, _status_page_id: str | None = None) None
class betterstack.uptime.UptimeAPI(bearer_token: str, retries: int = 3, backoff_factor: float = 0.5, timeout: float = 30.0, max_workers: int = 5)[source]

Bases: PaginatedAPI

BetterStack Uptime API client.

This is the main client class for interacting with the BetterStack Uptime API. It is pre-configured with the correct base URL and supports concurrent fetching of paginated results.

Example:
>>> api = UptimeAPI("your-bearer-token")
>>> monitors = list(Monitor.get_all_instances(api))
Attributes:

BETTERSTACK_API_URL: The base URL for the BetterStack Uptime API.

Initialize UptimeAPI with bearer token authentication.

Args:

bearer_token: Bearer token for API authentication. retries: Number of retries for failed requests. backoff_factor: Backoff factor for retry delays. timeout: Default timeout for requests in seconds. max_workers: Maximum number of threads for concurrent page fetching.

BETTERSTACK_API_URL = 'https://uptime.betterstack.com/api/v2/'
__init__(bearer_token: str, retries: int = 3, backoff_factor: float = 0.5, timeout: float = 30.0, max_workers: int = 5) None[source]

Initialize UptimeAPI with bearer token authentication.

Args:

bearer_token: Bearer token for API authentication. retries: Number of retries for failed requests. backoff_factor: Backoff factor for retry delays. timeout: Default timeout for requests in seconds. max_workers: Maximum number of threads for concurrent page fetching.

exception betterstack.uptime.ValidationError[source]

Bases: BetterStackError

Local validation error (e.g., invalid parameters).

betterstack.uptime.filter_on_attribute(objects: list[T], attribute: str, value: Any) list[T][source]

Filter a list of objects by attribute value.

This function filters a list of objects, returning only those where the specified attribute matches the given value.

Args:

objects: List of objects to filter. attribute: Name of the attribute to check. value: Value the attribute should match.

Returns:

A filtered list containing only objects where the attribute matches.

Example:
>>> monitors = [monitor1, monitor2, monitor3]
>>> paused_monitors = filter_on_attribute(monitors, "paused", True)