Skip to content

Cloud API Overview

pydoover provides two API clients for interacting with the Doover platform from Python code:

  • DataClient communicates with the Data API for working with channels, messages, aggregates, notifications, alarms, and WebSocket connections.
  • ControlClient communicates with the Control API for managing agents, applications, devices, organisations, and other platform resources.

Both clients come in synchronous and asynchronous variants, so you can pick the one that fits your application architecture.

Data API vs Control API

The two APIs serve different roles in the Doover platform:

Data APIControl API
Client classDataClient / AsyncDataClientControlClient / AsyncControlClient
Default base URLhttps://data.doover.com/apihttps://api.doover.com
PurposeReal-time telemetry and messagingResource management and configuration
Key operationsChannels, messages, timeseries, alarms, notificationsAgents, apps, devices, organisations

Installation

Both clients are included in the pydoover package. Install it with pip or uv:

pip install pydoover

Quick Example

Here is a minimal example that creates a Data API client, lists channels for an agent, and prints them:

from pydoover.api import DataClient

# Create a client using a saved profile
client = DataClient(profile="default")

# List all channels for an agent
channels = client.list_channels(agent_id=12345)
for ch in channels:
    print(f"{ch.name}: {ch.id}")

# Always close the client when done
client.close()

For the Control API, the pattern is similar but uses dynamic resource discovery:

from pydoover.api import ControlClient

client = ControlClient(profile="default")

# Get the methods available for the Agent model
methods = client.get_control_methods("Agent")

# Retrieve a specific agent
agent = methods.get(agent_id=12345)
print(agent.name)

client.close()

Authentication

Both clients handle authentication automatically. You can authenticate using:

  • Profile name -- loads credentials from ~/.doover/config
  • Explicit token -- pass a bearer token directly
  • Client credentials -- use a client_id and client_secret pair (Data API only)
  • Auth object -- provide a pre-configured auth client instance

Tokens are refreshed automatically before they expire. See Authentication for full details.

Retry and Timeout Behaviour

Both clients include built-in retry logic with exponential backoff:

  • Max retries: 3 (configurable via max_retries)
  • Base delay: 1 second between retries, doubling each attempt
  • Timeout: 60 seconds per request (configurable via timeout)

Server errors (5xx) and network timeouts trigger retries. Client errors (4xx) are raised immediately as exceptions.

# Customise retry and timeout settings
client = DataClient(
    profile="default",
    max_retries=5,
    timeout=120.0,
)

Context Manager Support

Both clients support the context manager protocol, which ensures resources are cleaned up properly:

# Sync client as context manager
with DataClient(profile="default") as client:
    channels = client.list_channels(agent_id=12345)

The async variants use async with:

# Async client as context manager
async with AsyncDataClient(profile="default") as client:
    channels = await client.list_channels(agent_id=12345)

Error Handling

API errors are raised as typed exceptions based on the HTTP status code:

  • BadRequestError (400) -- invalid request parameters
  • UnauthorizedError (401) -- missing or expired authentication
  • ForbiddenError (403) -- insufficient permissions
  • NotFoundError (404) -- resource does not exist
  • HTTPError -- any other non-2xx response

All exceptions are importable from pydoover.models.data.exceptions.

from pydoover.models.data.exceptions import NotFoundError

try:
    channel = client.fetch_channel(agent_id=12345, channel_name="nonexistent")
except NotFoundError:
    print("Channel not found")

Next Steps