Observability exports (Prometheus, Datadog, Grafana Cloud)
Tested with: API v1 · Prometheus 3 · Datadog Agent 7 (OpenMetrics check) · Grafana Alloy 1.x
Every organization has a Prometheus endpoint with one series per instance: status, size, storage and the metered usage of the latest complete hour (compute, storage, egress, connections, backups). Point any Prometheus-compatible collector at it with an API key.
GET https://api.databasezy.com/v1/orgs/{org_id}/metricsAuthorization: Bearer zb_...Create a scrape key
Section titled “Create a scrape key”Create a key that can only read usage. It cannot see credentials or change anything:
curl -s https://api.databasezy.com/v1/orgs/$ORG/api-keys \ -H "Authorization: Bearer $ADMIN_KEY" -H 'Content-Type: application/json' \ -d '{"name":"metrics-scraper","role":"viewer","scopes":["usage:read"]}'Store the returned key in your collector’s secret store. A key without usage:read gets 403.
What you get
Section titled “What you get”The response is Prometheus text format 0.0.4. Every series carries org_id, instance_id, instance
(the name), project_id, engine, region and team_id labels.
| Metric | Type | Meaning |
|---|---|---|
zerobase_instance_info | gauge | Always 1; labels add status, size, placement, engine_version |
zerobase_instance_up | gauge | 1 while the instance is ready, 0 when paused, provisioning or failed |
zerobase_instance_storage_allocated_gigabytes | gauge | Provisioned storage |
zerobase_instance_replicas | gauge | Read replicas |
zerobase_usage_compute_cents | gauge | Compute charge for the latest complete hour, in USD cents (size price x running time, before the plan credit) |
zerobase_usage_cu_hours | gauge | Compute capacity units (1 CU = 1 vCPU + 4 GiB) used in the hour; a capacity view, not a price |
zerobase_usage_storage_used_gb | gauge | Storage actually used |
zerobase_usage_egress_gb | gauge | Egress in the hour |
zerobase_usage_connections | gauge | Connections metered in the hour |
zerobase_usage_<metric> | gauge | Every other metered dimension (backup_gb_hours, replica_compute_cents, …) |
zerobase_usage_period_start_seconds | gauge | Start of the hour the usage series describe |
zerobase_metering_up | gauge | 0 when usage could not be read (instance series are still served) |
Usage is hourly, so a scrape interval of 60 s is plenty; 5 minutes is fine. Scraping counts against the normal API rate limit (600 requests per minute per key).
Prometheus
Section titled “Prometheus”scrape_configs: - job_name: databasezy scheme: https metrics_path: /v1/orgs/org_01J8XXXXXXXXXXXXXXXXXXXXXX/metrics scrape_interval: 60s authorization: type: Bearer credentials_file: /etc/prometheus/secrets/databasezy-key static_configs: - targets: ["api.databasezy.com"]Alert when an instance stops serving:
groups: - name: databasezy rules: - alert: DatabasezyInstanceDown expr: zerobase_instance_up == 0 and on (instance_id) zerobase_instance_info{status!="paused"} for: 5m labels: { severity: page } annotations: summary: "{{ $labels.instance }} ({{ $labels.engine }}) is not ready" - alert: DatabasezyStorageAlmostFull expr: zerobase_usage_storage_used_gb / zerobase_instance_storage_allocated_gigabytes > 0.85 for: 1h annotations: summary: "{{ $labels.instance }} uses over 85% of its storage"Grafana Cloud (Alloy)
Section titled “Grafana Cloud (Alloy)”Grafana Alloy scrapes the endpoint and remote-writes to your Grafana Cloud Prometheus stack:
prometheus.scrape "databasezy" { targets = [{ "__address__" = "api.databasezy.com" }] scheme = "https" metrics_path = "/v1/orgs/org_01J8XXXXXXXXXXXXXXXXXXXXXX/metrics" scrape_interval = "60s" bearer_token = sys.env("DATABASEZY_METRICS_KEY") forward_to = [prometheus.remote_write.grafana_cloud.receiver]}
prometheus.remote_write "grafana_cloud" { endpoint { url = "https://prometheus-prod-13-prod-us-east-0.grafana.net/api/prom/push" basic_auth { username = sys.env("GRAFANA_CLOUD_PROM_USER") password = sys.env("GRAFANA_CLOUD_API_KEY") } }}The older Grafana Agent (static mode) takes the same values under metrics.configs[].scrape_configs,
with authorization: { type: Bearer, credentials: ... }.
Datadog
Section titled “Datadog”Use the Agent’s OpenMetrics check. Add conf.d/openmetrics.d/conf.yaml:
init_config:
instances: - openmetrics_endpoint: https://api.databasezy.com/v1/orgs/org_01J8XXXXXXXXXXXXXXXXXXXXXX/metrics namespace: databasezy metrics: - zerobase_instance_.* - zerobase_usage_.* - zerobase_metering_up headers: Authorization: "Bearer ENC[databasezy_metrics_key]" min_collection_interval: 60 tags: - "source:databasezy"ENC[...] resolves through the Agent’s secrets management;
a plain value works for a first test. Restart the Agent, then check datadog-agent status for the
openmetrics instance. Metrics appear as databasezy.zerobase_instance_up and friends, with the labels as tags,
so a dashboard widget on sum:databasezy.zerobase_usage_compute_cents{*} by {instance} shows compute spend per instance.
On Kubernetes, put the same instance under the Datadog Helm chart’s datadog.confd or a cluster check;
the endpoint is not in your cluster, so no pod annotation discovery is involved.
Troubleshooting
Section titled “Troubleshooting”| Symptom | Cause |
|---|---|
401 | Key revoked, expired or suspended by an automatic security response (the org admin can lift a suspension) |
403 required_permission: usage:read | The key lacks the usage:read scope |
404 | The org id in the path is not the key’s org |
zerobase_metering_up 0 | Usage is temporarily unavailable; instance series are still current |
No zerobase_usage_* series for a new instance | Usage appears after its first complete metered hour |