datadog-api-client
datadog-api-client is Datadog's generated Python SDK for its public v1 and v2 HTTP APIs. It supplies a Configuration object, synchronous, threaded, and optional asyncio transports, per-resource API classes, and hundreds of typed request and response models for monitors, dashboards, logs, metrics, incidents, users, integrations, and newer products. It manages Datadog resources and submits data through public endpoints; it is not the Datadog Agent, ddtrace, or an application instrumentation library.
The right default for broad imperative Datadog automation in Python, especially when generated request models prevent payload mistakes. For one endpoint or declarative infrastructure, raw HTTP or an IaC provider can be much easier to maintain.
Use it if
- You automate Datadog monitors, dashboards, incidents, users, integrations, or other public API resources from Python
- You want generated models and method signatures instead of hand-building Datadog JSON and authentication headers
- You need paging helpers, configurable retry, proxies, regional Datadog sites, or an optional asyncio transport
- You want examples generated against the same OpenAPI description as the client
- You want to instrument Python application traces: install ddtrace or an OpenTelemetry integration, because this package calls management and intake APIs
- You only call one simple endpoint and value a small surface: generated v1 and v2 packages contain a very large model and import tree that can feel disproportionate
- You need a stable hand-designed API: classes and methods track Datadog's OpenAPI schemas, some operations are marked unstable, and new product fields can cause generated-code churn
- You expect one credential to be enough for every operation: the README uses both DD_API_KEY and DD_APP_KEY by default, while endpoint permissions also depend on the application key's scopes and the Datadog account
- You cannot keep site configuration explicit: US, EU, US3, US5, AP1, AP2, and government organizations use different hosts, and the default site can send valid credentials to the wrong Datadog endpoint
Setup reality
pip install datadog-api-client supports the synchronous urllib3 transport on Python 3.8 or newer. By default Configuration reads DD_API_KEY and DD_APP_KEY; these are different credentials, and management calls commonly need both. Use restricted application-key scopes where Datadog supports them and keep both values in a secret manager. The Agent's local configuration does not automatically make these environment variables available to your script. Site selection is mandatory outside the default datadoghq.com organization: set configuration.server_variables['site'] to the exact Datadog site, such as datadoghq.eu, before constructing the client. The package mirrors two API generations, so imports include datadog_api_client.v1 or .v2 and model names can be long. Use the generated example for the exact endpoint version rather than guessing. The normal ApiClient is a context manager and should be closed; create it once for a batch instead of for every item. Retry is off by default. Setting enable_retry handles rate-limit responses with a documented default retry count, while a custom urllib3 Retry can include server errors and takes precedence over enable_retry, retry_backoff_factor, and max_retries. Retrying create or update calls needs an idempotency decision, not just a transport toggle. Debug mode logs requests and can expose headers or payloads, so do not enable it casually in production. Proxy configuration is a URL string on Configuration. Gzip responses are enabled unless compress is false. Async support is not in the base install: use pip install 'datadog-api-client[async]', which adds aiosonic, then AsyncApiClient in an async with block. ThreadedApiClient is a separate synchronous option whose API methods return AsyncResult and require .get(). Endpoint list methods do not all paginate identically, but generated *_with_pagination methods return iterables that make additional requests as consumed. Unstable operations refuse to run until configuration.unstable_operations[method_name] is true, which is a useful warning that the contract can break. Models validate fields locally, but API errors still raise ApiException with status, parsed body, and headers. Treat those bodies as potentially sensitive, especially when logging failed monitor queries or user-management calls.
Patterns
Validate configured credentialsvalidate-api-key
from datadog_api_client import ApiClient, Configuration
from datadog_api_client.v1.api.authentication_api import AuthenticationApi
configuration = Configuration()
with ApiClient(configuration) as client:
result = AuthenticationApi(client).validate()
print(result.valid)Configuration reads DD_API_KEY and DD_APP_KEY by default; endpoint authorization still depends on key scopes.
Target a regional Datadog siteselect-datadog-site
from datadog_api_client import ApiClient, Configuration
configuration = Configuration()
configuration.server_variables['site'] = 'datadoghq.eu'
with ApiClient(configuration) as client:
call_api(client)Use the site assigned to your organization; valid credentials sent to the default US host will not access an EU organization.
Iterate through monitors with paginationlist-monitors
from datadog_api_client import ApiClient, Configuration
from datadog_api_client.v1.api.monitors_api import MonitorsApi
with ApiClient(Configuration()) as client:
monitors = MonitorsApi(client).list_monitors_with_pagination(
monitor_tags='service:checkout',
page_size=100,
)
for monitor in monitors:
print(monitor.id, monitor.name)The returned iterable fetches more pages as you consume it, so stopping early can avoid unnecessary requests.
Create a log alert monitorcreate-monitor
from datadog_api_client import ApiClient, Configuration
from datadog_api_client.v1.api.monitors_api import MonitorsApi
from datadog_api_client.v1.model.monitor import Monitor
from datadog_api_client.v1.model.monitor_type import MonitorType
body = Monitor(
name='Checkout errors',
type=MonitorType.LOG_ALERT,
query='logs("service:checkout status:error").index("main").rollup("count").last("5m") > 10',
message='Checkout errors are elevated',
tags=['service:checkout', 'managed-by:python'],
)
with ApiClient(Configuration()) as client:
created = MonitorsApi(client).create_monitor(body=body)Generated models validate structure, but Datadog still validates the monitor query and account permissions server-side.
Retry rate-limited requestsenable-rate-limit-retry
from datadog_api_client import ApiClient, Configuration
configuration = Configuration()
configuration.enable_retry = True
configuration.max_retries = 5
with ApiClient(configuration) as client:
call_api(client)The built-in switch is documented for 429 responses; decide separately whether mutating operations are safe to retry.
Provide an explicit urllib3 retry policyset-custom-retry
import urllib3
from datadog_api_client import ApiClient, Configuration
retry = urllib3.util.Retry(
total=5,
backoff_factor=2,
status_forcelist=[429, 500, 502, 503, 504],
allowed_methods=['GET'],
)
configuration = Configuration(retry_policy=retry)
with ApiClient(configuration) as client:
call_read_only_api(client)A custom retry policy overrides enable_retry, retry_backoff_factor, and max_retries; limiting methods avoids repeating writes blindly.
Call an API with asynciouse-async-client
import asyncio
from datadog_api_client import AsyncApiClient, Configuration
from datadog_api_client.v1.api.dashboards_api import DashboardsApi
async def main():
async with AsyncApiClient(Configuration()) as client:
dashboards = await DashboardsApi(client).list_dashboards()
print(dashboards)
asyncio.run(main())Install datadog-api-client[async] first; the base package does not include the aiosonic transport extra.
Run calls through the threaded clientuse-threaded-client
from datadog_api_client import Configuration, ThreadedApiClient
from datadog_api_client.v1.api.dashboards_api import DashboardsApi
with ThreadedApiClient(Configuration()) as client:
pending = DashboardsApi(client).list_dashboards()
dashboards = pending.get()Methods return AsyncResult under ThreadedApiClient; forgetting .get() leaves you with the handle rather than the response.
Explicitly enable an unstable operationcall-unstable-endpoint
from datadog_api_client import ApiClient, Configuration
from datadog_api_client.v2.api.incidents_api import IncidentsApi
configuration = Configuration()
configuration.unstable_operations['list_incidents'] = True
with ApiClient(configuration) as client:
for incident in IncidentsApi(client).list_incidents_with_pagination():
print(incident.id)The operation name, not the API class name, is the opt-in key; unstable contracts can change between releases.
Inspect structured API failureshandle-api-errors
from datadog_api_client.exceptions import ApiException
try:
call_api(client)
except ApiException as error:
logger.error('Datadog request failed', extra={
'status': error.status,
'body': error.body,
})
raiseApiException can contain response headers and a parsed body; redact credentials and sensitive query data before logging.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| datadog | PyPI | You maintain code on Datadog's older, smaller datadogpy client and do not need the generated modern surface |
| requests | PyPI | You call only one or two stable endpoints and prefer explicit HTTP over hundreds of generated models |
| pulumi-datadog | PyPI | You want declarative Datadog infrastructure under Pulumi state instead of imperative API scripts |