Skip to content

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)
Warning

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

ParameterTypeDefaultDescription
base_urlstrhttps://data.doover.com/apiData API base URL
agent_idintNoneDefault agent ID for all requests
organisation_idintNoneDefault organisation context
max_retriesint3Number of retry attempts for server errors
timeoutfloat60.0Request 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