Skip to content
238 changes: 238 additions & 0 deletions content/manuals/enterprise/reports/_index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
---
title: Usage reports
description: Learn how to retrieve enterprise usage reports for your Docker organization using the Reports API.
keywords: docker, enterprise, reports, usage, pulls, api, csv, organization access token, oat
weight: 20
params:
sidebar:
group: Enterprise
---

Docker provides daily usage reports for organizations with a Docker Business
subscription. These reports contain pull activity data for your organization and
are available as CSV downloads through the Reports API.

Reports are generated automatically. You use the API to list what is available
and download the files you need.

## Prerequisites

Before you begin, ensure you have:

- A [Docker Business subscription](/subscription/details/)
- One of the following:
- Organization owner role
- A custom role that includes the **report-read** permission
- `curl` installed for making API requests
- `jq` installed for JSON parsing (optional, for formatting responses)

## Authentication

The Reports API requires an Organization Access Token (OAT). OATs are
org-scoped tokens designed for machine-to-machine access, making them
suitable for automated report retrieval workflows. Personal Access Tokens
(PATs) are not supported.

1. [Create an organization access token](/enterprise/security/access-tokens/)
and select the **Report Read** scope under Organization permissions.

2. Set your variables:

```bash
ORG="<your-org-name>"
TOKEN="<your-organization-access-token>"
```

3. Test the token:

```console
$ curl -s "https://api.docker.com/enterprise-data/v1/orgs/$ORG/reports" \
-H "Authorization: Bearer $TOKEN" | jq .
```

You use this `TOKEN` value in the `Authorization: Bearer` header for all
subsequent API calls.

## List available report types

Discover which report types and cadences are available for your organization.

```console
$ curl -s "https://api.docker.com/enterprise-data/v1/orgs/$ORG/reports" \

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[HIGH] curl examples include /reports path segment not present in OpenAPI spec

All curl examples in this guide include /reports in the path (e.g., /orgs/$ORG/reports, /orgs/$ORG/reports/usage_pulls/daily), but the OpenAPI spec defines paths without this segment (e.g., /orgs/{org_name}, /orgs/{org_name}/{type}/{cadence}).

Both documents are new and were published together, yet they describe different URL structures. Please reconcile: either add the missing /reports segment to all four paths in api.yaml, or remove it from the guide's curl examples and reference table to match the spec.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in c8fe0a6. The OpenAPI spec paths now include /reports and match the curl examples.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perfect, thank you! I verified the commit and all four paths in the OpenAPI spec now correctly include "/reports" to match the curl examples and documentation. The discrepancy is resolved.

-H "Authorization: Bearer $TOKEN" | jq .
```

Example response:

```json
{
"report_types": [
{
"ReportType": "usage_pulls",
"Cadence": "daily"
}
]
}
```

Each entry represents a distinct combination of report type and cadence. Use
these values in subsequent calls.

## List reports

List available reports for a given type and cadence. Reports are returned in
reverse chronological order (most recent first).

```console
$ curl -s "https://api.docker.com/enterprise-data/v1/orgs/$ORG/reports/usage_pulls/daily" \
-H "Authorization: Bearer $TOKEN" | jq .
```

Example response:

```json
{
"reports": [
{
"ReportType": "usage_pulls",
"Cadence": "daily",
"Date": "2026-06-16",
"SizeBytes": 48210,
"Key": "my-org/usage_pulls/daily/2026-06-16.csv"
},
{
"ReportType": "usage_pulls",
"Cadence": "daily",
"Date": "2026-06-15",
"SizeBytes": 51003,
"Key": "my-org/usage_pulls/daily/2026-06-15.csv"
}
],
"next_page_token": ""
}
```

### Pagination

Results are paginated with a default page size of 30 and a maximum of 100.
Use the `page_size` and `page_token` query parameters to control pagination.

```console
$ curl -s "https://api.docker.com/enterprise-data/v1/orgs/$ORG/reports/usage_pulls/daily?page_size=10" \
-H "Authorization: Bearer $TOKEN" | jq .
```

When `next_page_token` is non-empty, pass it as `page_token` to fetch the next
page:

```console
$ curl -s "https://api.docker.com/enterprise-data/v1/orgs/$ORG/reports/usage_pulls/daily?page_size=10&page_token=NEXT_TOKEN" \
-H "Authorization: Bearer $TOKEN" | jq .
```

## Download a report

Download the CSV file for a specific date. The API responds with a `302`
redirect to a pre-signed URL. With `curl -L`, the redirect is followed
automatically and the file is saved locally.

```console
$ curl -L -o "usage_pulls_2026-06-16.csv" \
"https://api.docker.com/enterprise-data/v1/orgs/$ORG/reports/usage_pulls/daily/2026-06-16/download" \
-H "Authorization: Bearer $TOKEN"
```

The pre-signed download URL expires after 15 minutes. If the link expires,
call the endpoint again to get a fresh URL.

### Download the latest report

Combine the list and download steps to always fetch the most recent report:

```bash
DATE=$(
curl -s "https://api.docker.com/enterprise-data/v1/orgs/$ORG/reports/usage_pulls/daily?page_size=1" \

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[MEDIUM] Download-latest script silently produces broken output when no reports exist

When the API returns an empty reports list, jq -r '.reports[0].Date' outputs the literal string null (not an empty string). The script then silently:

  • Creates a file named usage_pulls_null.csv
  • Makes a download request to .../daily/null/download, which returns a 404

Consider adding a guard to catch this case:

DATE=$(
  curl -s "https://api.docker.com/enterprise-data/v1/orgs/$ORG/reports/usage_pulls/daily?page_size=1" \
    -H "Authorization: Bearer $TOKEN" \
  | jq -r '.reports[0].Date // empty'
)

if [ -z "$DATE" ]; then
  echo "No reports available."
  exit 1
fi

curl -L -o "usage_pulls_${DATE}.csv" \
  "https://api.docker.com/enterprise-data/v1/orgs/$ORG/reports/usage_pulls/daily/${DATE}/download" \
  -H "Authorization: Bearer $TOKEN"

Using // empty makes jq output nothing (empty string) instead of null, so the shell check [ -z "$DATE" ] works correctly for both the no-reports and API-error cases.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in e983461. Added // empty to the jq expression and a shell guard that exits early with a message when no reports are available.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perfect! Thanks for the quick fix. The guard now correctly handles the empty reports case and prevents the script from creating broken files.

-H "Authorization: Bearer $TOKEN" \
| jq -r '.reports[0].Date // empty'
)

if [ -z "$DATE" ]; then
echo "No reports available."
exit 1
fi

curl -L -o "usage_pulls_${DATE}.csv" \
"https://api.docker.com/enterprise-data/v1/orgs/$ORG/reports/usage_pulls/daily/${DATE}/download" \
-H "Authorization: Bearer $TOKEN"
```

## Get report schema

Retrieve the schema for a specific report date. The schema describes the columns
in the CSV file.

```console
$ curl -s "https://api.docker.com/enterprise-data/v1/orgs/$ORG/reports/usage_pulls/daily/2026-06-16/schema" \
-H "Authorization: Bearer $TOKEN" | jq .
```

Example response:

```json
{
"category": "usage_pulls",
"fields": [
{
"name": "date",
"type": "string",
"description": "The date of the pull event (YYYY-MM-DD)."
},
{
"name": "repository",
"type": "string",
"description": "The repository that was pulled."
},
{
"name": "pull_count",
"type": "integer",
"description": "Number of pulls for the repository on this date."
}
]
}
```

Use the schema endpoint to programmatically discover column names and types
before processing a report.

## API reference

| Endpoint | Description |
|---|---|
| `GET /enterprise-data/v1/orgs/{org}/reports` | List available report types |
| `GET /enterprise-data/v1/orgs/{org}/reports/{type}/{cadence}` | List reports with pagination |
| `GET /enterprise-data/v1/orgs/{org}/reports/{type}/{cadence}/{date}/download` | Download a report (302 redirect) |
| `GET /enterprise-data/v1/orgs/{org}/reports/{type}/{cadence}/{date}/schema` | Get report column schema |

For the full API specification, see the
[Enterprise Data API reference](/reference/api/enterprise-data/latest/).

## Troubleshooting

### 401 Unauthorized

Your token is missing or invalid. Verify that you are passing the token as a
Bearer token in the `Authorization` header and that the token has not expired.

### 403 Forbidden

The authenticated user or token does not have permission to access reports for
this organization. Verify that:

- The user has the organization owner role or a custom role with the
**report-read** permission.
- The organization has an active Docker Business subscription.

### 404 Not Found

The requested report type, cadence, or date does not exist. Use the list
endpoints to discover available reports before attempting a download.
5 changes: 5 additions & 0 deletions content/reference/api/enterprise-data/_index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
title: Enterprise Data API
build:
render: never
---
22 changes: 22 additions & 0 deletions content/reference/api/enterprise-data/changelog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
description: Docker Enterprise Data API changelog
title: Docker Enterprise Data API changelog
linkTitle: Changelog
keywords: docker enterprise, data api, whats new, release notes, api, changelog
weight: 2
toc_min: 1
toc_max: 2
---

Here you can learn about the latest changes, new features, bug fixes, and known
issues for the Docker Enterprise Data API.

---

## 2026-06-17

### New

- Initial release of the Enterprise Data API
- Usage reports endpoints: list report types, list reports, download, schema
- Authentication via Personal Access Tokens (PAT) and Organization Access Tokens (OAT)
26 changes: 26 additions & 0 deletions content/reference/api/enterprise-data/deprecated.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
description: Deprecated Docker Enterprise Data API endpoints
keywords: deprecated
title: Deprecated Docker Enterprise Data API endpoints
linkTitle: Deprecated
weight: 3
---

This page provides an overview of endpoints that are deprecated in the Docker Enterprise Data API.

## Endpoint deprecation policy

As changes are made to the Docker Enterprise Data API there may be times when existing endpoints need to be removed or replaced with newer endpoints. Before an existing endpoint is removed it is labeled as "deprecated" within the documentation. After some time it may be removed.

## Deprecated endpoints

The following table provides an overview of the current status of deprecated endpoints:

**Deprecated**: the endpoint is marked "deprecated" and should no longer be used.
The endpoint may be removed, disabled, or change behavior in a future release.

**Removed**: the endpoint was removed, disabled, or hidden.

---

No endpoints are currently deprecated.
7 changes: 7 additions & 0 deletions content/reference/api/enterprise-data/latest.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
layout: api
description: Reference documentation and OpenAPI specification for the Docker Enterprise Data API.
title: Docker Enterprise Data API reference
linkTitle: Latest
weight: 1
---
Loading