Documentation 40

Guide · Datadog

How do I test a Datadog integration without a real organization?

You do not need one. Point your client at a read-only Datadog replica that already holds the olympus-labs data set, and your code runs unchanged.

01 / The one change

Swap the base URL. Nothing else.

Your client talks to api.datadoghq.com. Point it at api.dd.sandboxapis.dev instead: same paths, same JSON, same headers, same status codes. No organization to create, no seed script.

Datadog has no pinned host yet, so this page uses the live host, api.dd.sandboxapis.dev, which re-rolls daily: assert on what a re-roll keeps, and switch to a pin when one is registered.

02 / Run it now

One request, no account.

request.sh
curl -s "https://api.dd.sandboxapis.dev/api/v1/monitor"

It answers with the monitors of the data set, one per alerting rule its services carry, each with its query over the trace metrics, its tags and its state, in Datadog's own monitor JSON.

With a real client, the verified quickstart for datadog-api-client runs against the live host on every check. It prints how many monitors the data set carries and the services they watch, then one request-count series per service over the last 24 hours.

python
# pip install datadog-api-client==2.62.0

import time
from datadog_api_client import ApiClient, Configuration
from datadog_api_client.v1.api.monitors_api import MonitorsApi
from datadog_api_client.v1.api.metrics_api import MetricsApi

config = Configuration(host="https://api.dd.sandboxapis.dev")   # the only line that changes (DD_SITE is checked against Datadog's own sites)
config.api_key["apiKeyAuth"] = "any-token"                       # any key is accepted
config.api_key["appKeyAuth"] = "any-token"

with ApiClient(config) as client:
    monitors = MonitorsApi(client).list_monitors()
    print(len(monitors), "monitors, services:", ", ".join(sorted({t for m in monitors for t in m.tags if t.startswith("service:")})))
    now = int(time.time())
    q = MetricsApi(client).query_metrics(_from=now - 86400, to=now, query="avg:trace.http.request.hits{*} by {service}")
    print("series:", ", ".join(sorted(s.scope for s in q.series)))

What it prints always contains monitors, services:, service:pipeline- and series:.

03 / Writes

A write gets Datadog's own error shape.

Every host is read-only. A write answers 403 with Datadog's own error body, naming what you tried, so your client's existing error handling meets a shape it knows.

request.sh
curl -s -X POST "https://api.dd.sandboxapis.dev/api/v1/monitor" -H 'content-type: application/json' -d '{"name":"probe","type":"query alert","query":"avg(last_5m):avg:system.cpu.user{*} > 90"}'

The body is Datadog's own error envelope: errors is a one-item array whose message says the data set is read-only, names the method and path you tried, and links the coverage page.

04 / Where it stops

Coverage is counted, not claimed.

436 of 879 Datadog read surfaces are served and verified against Datadog's own published spec. A call to one that is not covered returns a 404 with an X-SandboxAPIs-Coverage header, never invented data. The row-by-row list is on the Datadog reference and the coverage page.

Next: read the Datadog quickstart, or run the four-hop walk to watch one incident cross four services.

What this is not

Read this before you rely on it.

SandboxAPIs is read-only: a write returns the provider's own error unless your key has opted in to scratch writes, and those never reach anybody else. Coverage is bounded, and the manifest that says exactly where it stops is public. The data is a simulated company, not yours and not a copy of anybody's. And it reproduces what each vendor documents and publishes, not the vendor's undocumented behaviour, so keep one test against the real service for that.