Skip to content

honeyhive

HoneyHive Python SDK - LLM Observability and Evaluation Platform

HoneyHive

Main HoneyHive API client.

Provides an ergonomic interface to the HoneyHive API with both sync and async methods.

Each method's "Accepted keys" section names the API keys it can send. A project API key is passed as api_key, an ingestion API key as ingestion_api_key, and a data plane fine-grained API key as data_plane_api_key. Where a method names a typed key beside a project API key, the project API key is deprecated. Each key type, and where to create one, is described at https://docs.honeyhive.ai/v2/workspace/api-keys#key-types.

Example::

client = HoneyHive(api_key="your-api-key")

# Sync
configs = client.configurations.list()

# Async
configs = await client.configurations.list_async()

Attributes:

Name Type Description
configurations

API for managing configurations.

datapoints

API for managing datapoints.

datasets

API for managing datasets.

events

API for managing events.

experiments

API for managing experiment runs.

metrics

API for managing metrics.

sessions

API for managing sessions.

Source code in src/honeyhive/api/client.py
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017
4018
4019
4020
4021
4022
4023
4024
4025
4026
4027
4028
4029
4030
4031
4032
4033
4034
4035
4036
4037
4038
4039
4040
4041
4042
4043
4044
4045
4046
4047
4048
4049
4050
4051
4052
4053
4054
4055
4056
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066
4067
4068
4069
4070
4071
4072
4073
4074
4075
4076
4077
4078
4079
4080
4081
4082
4083
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
4096
4097
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108
4109
4110
4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
4121
4122
4123
4124
4125
4126
4127
4128
4129
4130
4131
4132
4133
4134
4135
4136
4137
4138
4139
4140
4141
4142
4143
4144
4145
4146
4147
4148
4149
4150
4151
4152
4153
4154
4155
4156
4157
4158
4159
4160
4161
4162
4163
4164
4165
4166
4167
4168
4169
4170
4171
4172
4173
4174
4175
4176
4177
4178
4179
4180
4181
4182
4183
4184
4185
4186
4187
4188
4189
4190
4191
4192
4193
4194
4195
4196
4197
4198
4199
4200
4201
4202
4203
4204
4205
4206
4207
4208
4209
4210
4211
4212
4213
4214
4215
4216
4217
4218
4219
4220
4221
4222
4223
4224
4225
4226
4227
4228
4229
4230
4231
4232
4233
4234
4235
4236
4237
4238
4239
4240
4241
4242
4243
4244
4245
4246
4247
4248
4249
4250
4251
4252
4253
4254
4255
4256
4257
4258
4259
4260
4261
4262
4263
4264
4265
4266
4267
4268
4269
4270
4271
4272
4273
4274
4275
4276
4277
4278
4279
class HoneyHive:
    """Main HoneyHive API client.

    Provides an ergonomic interface to the HoneyHive API with both
    sync and async methods.

    Each method's "Accepted keys" section names the API keys it can send. A
    project API key is passed as ``api_key``, an ingestion API key as
    ``ingestion_api_key``, and a data plane fine-grained API key as
    ``data_plane_api_key``. Where a method names a typed key beside a project
    API key, the project API key is deprecated. Each key type, and where to
    create one, is described at
    <https://docs.honeyhive.ai/v2/workspace/api-keys#key-types>.

    Example::

        client = HoneyHive(api_key="your-api-key")

        # Sync
        configs = client.configurations.list()

        # Async
        configs = await client.configurations.list_async()

    Attributes:
        configurations: API for managing configurations.
        datapoints: API for managing datapoints.
        datasets: API for managing datasets.
        events: API for managing events.
        experiments: API for managing experiment runs.
        metrics: API for managing metrics.
        sessions: API for managing sessions.
    """

    # The published constructor keeps every parameter it has ever accepted until
    # v2.0, so its argument count is fixed by compatibility and the suppression
    # below stays until then. This method therefore holds only the frozen
    # signature and the deprecation warnings; the construction logic lives in
    # _initialize, where the argument limit and every other lint still apply.
    # pylint: disable-next=too-many-arguments
    def __init__(
        self,
        api_key: Optional[str] = None,
        # `project` sits at positional slot #2 to mirror the legacy SDK shape
        # — pre-1.0 callers wrote `HoneyHive("key", "project-name")` positionally.
        # Keeping the slot reserved means those calls still execute (with a
        # DeprecationWarning) instead of binding the value to `base_url` or
        # raising TypeError. The argument is otherwise ignored.
        project: Optional[str] = None,
        *,
        ingestion_api_key: Optional[str] = None,
        data_plane_api_key: Optional[str] = None,
        # Primary URL parameter
        base_url: Optional[str] = None,
        # Backwards compatible alias for base_url
        server_url: Optional[str] = None,
        cp_base_url: Optional[str] = None,
        timeout: Optional[float] = None,
        retry_config: Optional[Any] = None,
        rate_limit_calls: Optional[int] = None,
        rate_limit_window: Optional[float] = None,
        max_connections: Optional[int] = None,
        max_keepalive: Optional[int] = None,
        test_mode: Optional[bool] = None,
        verbose: Optional[bool] = None,
        tracer_instance: Optional[Any] = None,
    ) -> None:
        """Initialize the HoneyHive client.

        Deprecated parameters are accepted so existing calls keep working; each
        one passed emits a ``DeprecationWarning`` and is otherwise ignored. The
        client is built by ``_initialize`` from the parameters still in use.

        Args:
            api_key: HoneyHive API key (typically starts with ``hh_``).
                     Falls back to HH_API_KEY environment variable.
            ingestion_api_key: Ingestion API key (starts with ``hh_ingst_``) sent
                     with requests that create sessions or write events. Falls
                     back to the HH_INGESTION_API_KEY environment variable, then
                     to api_key. A value that is set but is not an ingestion key
                     raises ValueError here, at construction.
            data_plane_api_key: Fine-grained data plane API key (starts with
                     ``hh_fgdp_``), the credential for the operations that name
                     a project in their path. Falls back to the
                     HH_DATA_PLANE_API_KEY environment variable. Without either,
                     those operations raise MissingApiKeyError before sending,
                     because they refuse api_key. A value that is set but is not
                     a fine-grained data plane key raises ValueError here, at
                     construction.
            project: Deprecated and ignored; will be removed in v2.0. The
                backend infers project context from the API key and session.
            base_url: API base URL for HoneyHive.
                      Falls back to HH_API_URL env var, then https://api.dp1.us.honeyhive.ai.
            server_url: Alias for base_url, kept for callers written against the
                older name; base_url wins when both are given.
            cp_base_url: Deprecated and ignored; will be removed in v2.0. The
                SDK uses a single base_url for all operations.
            timeout: Request timeout in seconds. Falls back to the HH_API_TIMEOUT
                env var, then to the SDK default of 5s. Pass a larger value when
                fetching large payloads (e.g. datasets.list for many datasets).
            retry_config: Retry configuration for ``events.export()`` /
                ``events.export_async()``, the only methods that retry. A
                ``RetryConfig`` is used as-is. When omitted, ``HH_MAX_RETRIES``
                sets the retry budget (default 3).
            rate_limit_calls: Deprecated and ignored; will be removed in v2.0.
            rate_limit_window: Deprecated and ignored; will be removed in v2.0.
            max_connections: Deprecated and ignored; will be removed in v2.0.
            max_keepalive: Deprecated and ignored; will be removed in v2.0.
            test_mode: Recorded and exposed as ``HoneyHive.test_mode``.
            verbose: Recorded and exposed as ``HoneyHive.verbose``.
            tracer_instance: Deprecated and ignored; will be removed in v2.0.
        """
        deprecated_parameters = (
            ("project", project),
            ("cp_base_url", cp_base_url),
            ("rate_limit_calls", rate_limit_calls),
            ("rate_limit_window", rate_limit_window),
            ("max_connections", max_connections),
            ("max_keepalive", max_keepalive),
            ("tracer_instance", tracer_instance),
        )
        for name, value in deprecated_parameters:
            if value is not None:
                message = (
                    f"The {name!r} parameter to HoneyHive() is deprecated and "
                    "ignored; it will be removed in v2.0. Remove it from "
                    "HoneyHive() calls."
                )
                warnings.warn(message, DeprecationWarning, stacklevel=2)
                logger.warning(message)

        self._initialize(
            api_key=api_key,
            ingestion_api_key=ingestion_api_key,
            data_plane_api_key=data_plane_api_key,
            base_url=base_url,
            server_url=server_url,
            timeout=timeout,
            retry_config=retry_config,
            test_mode=test_mode,
            verbose=verbose,
        )

    def _initialize(
        self,
        *,
        api_key: Optional[str],
        ingestion_api_key: Optional[str],
        data_plane_api_key: Optional[str],
        base_url: Optional[str],
        server_url: Optional[str],
        timeout: Optional[float],
        retry_config: Optional[Any],
        test_mode: Optional[bool],
        verbose: Optional[bool],
    ) -> None:
        """Build the client from the parameters still in use.

        ``__init__`` holds the published signature and drops the deprecated
        parameters before calling here.
        """
        connection = ResolvedConfig.resolve(
            api_key=api_key,
            ingestion_api_key=ingestion_api_key,
            data_plane_api_key=data_plane_api_key,
            api_url=base_url or server_url,
        )
        self._api_key = connection.api_key or ""
        self._ingestion_api_key = connection.ingestion_api_key or ""
        self._data_plane_api_key = connection.data_plane_api_key or ""
        resolved_base_url = connection.api_url

        # Exposed through the timeout, test_mode, verbose and retry_config properties.
        self._timeout = timeout
        self._test_mode = test_mode if test_mode is not None else False
        self._verbose = verbose if verbose is not None else False
        self._retry_config = RetryConfig.from_optional(retry_config)

        # Create API config. The request timeout is resolved from the explicit
        # arg > HH_API_TIMEOUT env var; when neither is set we omit the key so
        # the APIConfig default (5.0s) is preserved. Note: passing timeout=None
        # to HoneyHive() keeps the default (None means "unset" here), whereas
        # APIConfig(timeout=None) disables timeouts at the low level.
        api_config_kwargs: Dict[str, Any] = {
            "base_path": resolved_base_url,
            "access_token": self._api_key,
        }
        resolved_timeout = _resolve_api_timeout(timeout)
        if resolved_timeout is not None:
            api_config_kwargs["timeout"] = resolved_timeout
        self._api_config = APIConfig(**api_config_kwargs)

        # Only the namespaces with wrappers for a typed key's operations take
        # that key; they derive the configuration for those requests from
        # `_api_config` and the key at call time (see
        # BaseAPI._typed_api_config), so there is one configuration object for
        # a caller to mutate. Every other namespace sends `_api_config` as it
        # always has.
        self.charts = ChartsAPI(
            self._api_config, data_plane_api_key=self._data_plane_api_key
        )
        self.configurations = ConfigurationsAPI(self._api_config)
        self.datapoints = DatapointsAPI(
            self._api_config, data_plane_api_key=self._data_plane_api_key
        )
        self.datasets = DatasetsAPI(
            self._api_config, data_plane_api_key=self._data_plane_api_key
        )
        self.events = EventsAPI(
            self._api_config,
            self._ingestion_api_key,
            retry_config=self._retry_config,
        )
        self.experiments = ExperimentsAPI(
            self._api_config, data_plane_api_key=self._data_plane_api_key
        )
        self.metrics = MetricsAPI(self._api_config)
        self.metric_versions = MetricVersionsAPI(self._api_config)
        self.sessions = SessionsAPI(self._api_config, self._ingestion_api_key)

        # Alias for backwards compatibility
        self.evaluations = self.experiments

    @property
    def test_mode(self) -> bool:
        """Return whether client is in test mode."""
        return self._test_mode

    @property
    def verbose(self) -> bool:
        """Return whether verbose mode is enabled."""
        return self._verbose

    @property
    def timeout(self) -> Optional[float]:
        """Return the configured timeout."""
        return self._timeout

    @property
    def retry_config(self) -> RetryConfig:
        """Retry configuration used by ``events.export()`` / ``export_async()``."""
        return self._retry_config

    @property
    def api_config(self) -> APIConfig:
        """Access the underlying API configuration."""
        return self._api_config

    @property
    def api_key(self) -> str:
        """Get the HoneyHive API key."""
        return self._api_key

    @property
    def ingestion_api_key(self) -> str:
        """The ingestion API key, or ``""`` when api_key is used for ingestion too."""
        return self._ingestion_api_key

    @property
    def data_plane_api_key(self) -> str:
        """The fine-grained data plane API key, or ``""`` when none is configured."""
        return self._data_plane_api_key

    @property
    def server_url(self) -> str:
        """Get the HoneyHive API server URL."""
        return self._api_config.base_path

    @server_url.setter
    def server_url(self, value: str) -> None:
        """Set the HoneyHive API server URL."""
        self._api_config.base_path = value

test_mode property

test_mode: bool

Return whether client is in test mode.

verbose property

verbose: bool

Return whether verbose mode is enabled.

timeout property

timeout: Optional[float]

Return the configured timeout.

retry_config property

retry_config: RetryConfig

Retry configuration used by events.export() / export_async().

api_config property

api_config: APIConfig

Access the underlying API configuration.

api_key property

api_key: str

Get the HoneyHive API key.

ingestion_api_key property

ingestion_api_key: str

The ingestion API key, or "" when api_key is used for ingestion too.

data_plane_api_key property

data_plane_api_key: str

The fine-grained data plane API key, or "" when none is configured.

server_url property writable

server_url: str

Get the HoneyHive API server URL.

MissingApiKeyError

Bases: ValueError

Raised by an operation when no key it can use is configured.

It is raised before anything is sent. An ingestion operation uses the project API key when no ingestion key is configured, so it names the ingestion key only when neither is. An operation that takes the data plane key accepts no other key, so it names the data plane key whenever that key is absent.

Attributes:

Name Type Description
key_kind

The kind of key the operation requires.

Source code in src/honeyhive/api/_base.py
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
class MissingApiKeyError(ValueError):
    """Raised by an operation when no key it can use is configured.

    It is raised before anything is sent. An ingestion operation uses the
    project API key when no ingestion key is configured, so it names the
    ingestion key only when neither is. An operation that takes the data plane
    key accepts no other key, so it names the data plane key whenever that key
    is absent.

    Attributes:
        key_kind: The kind of key the operation requires.
    """

    def __init__(self, key_kind: ApiKeyKind) -> None:
        super().__init__(_MISSING_API_KEY_MESSAGES[key_kind])
        self.key_kind = key_kind

key_kind instance-attribute

key_kind = key_kind