Data Client
DataClient and AsyncDataClient are the primary interfaces for working with the Doover Data API. They provide methods for managing channels, messages, aggregates, alarms, notifications, and WebSocket connections.
Constructor
Both clients accept the same flexible set of authentication and configuration options. You do not need to provide a base_url -- it defaults to https://data.doover.com/api.
Using a profile
The simplest way to authenticate is with a saved profile from ~/.doover/config:
from pydoover.api import DataClient client = DataClient(profile="default")
Using an explicit token
If you already have a bearer token, pass it directly:
from datetime import datetime, timezone
client = DataClient(
token="eyJhbGciOiJSUzI1NiIs...",
token_expires=datetime(2026, 6, 1, tzinfo=timezone.utc),
)
The token_expires parameter is optional. If omitted, the client extracts the exp claim from the JWT automatically.
Using client credentials
For service accounts that authenticate with a client ID and secret:
client = DataClient(
client_id="my-service-id",
client_secret="my-service-secret",
)
This uses the DataService auth flow, which obtains and refreshes tokens automatically.
Using a pre-built auth object
If you need to share an auth client across multiple API clients, pass it directly:
from pydoover.api.auth import Doover2AuthClient
auth = Doover2AuthClient.from_profile("default")
client = DataClient(auth=auth)
When you pass an auth object, you cannot combine it with other auth parameters like profile, token, or client_id. The client will raise a ValueError if you do.
Key Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
base_url | str | https://data.doover.com/api | Data API base URL |
agent_id | int | None | Default agent ID for all requests |
organisation_id | int | None | Default organisation context |
max_retries | int | 3 | Number of retry attempts for server errors |
timeout | float | 60.0 | Request timeout in seconds |
Setting a default agent_id avoids repeating it on every method call:
# Set a default agent ID at client level client = DataClient(profile="default", agent_id=12345) # Now you can omit agent_id from individual calls channels = client.list_channels(agent_id=12345)
Context Manager Usage
The synchronous client can be used as a context manager, which automatically calls close() when the block exits:
with DataClient(profile="default") as client:
channels = client.list_channels(agent_id=12345)
for ch in channels:
print(ch.name)
# client is closed automatically here
Async Client
AsyncDataClient has the same API but all data methods are coroutines. Use async with to manage its lifecycle:
from pydoover.api import AsyncDataClient
async with AsyncDataClient(profile="default") as client:
channels = await client.list_channels(agent_id=12345)
for ch in channels:
print(ch.name)
The async client creates an aiohttp session internally. The context manager ensures both the HTTP session and the auth client are closed properly.
Basic Usage
This example demonstrates the most common workflow: creating a client, listing channels, posting a message, and closing the client.
from pydoover.api import DataClient
# 1. Create the client
client = DataClient(profile="default")
try:
# 2. List channels for an agent
channels = client.list_channels(agent_id=12345)
print(f"Found {len(channels)} channels")
# 3. Create a message on a channel
message = client.create_message(
agent_id=12345,
channel_name="telemetry",
data={"temperature": 22.5, "humidity": 65},
)
print(f"Created message {message.id}")
finally:
# 4. Always close the client
client.close()
Related Pages
- Channels -- channel operations in detail
- Messages -- message CRUD, iteration, and timeseries
- Authentication -- auth flows and token management
- Agents & Control API -- the ControlClient for resource management