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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Usage reports should go under Admin > Organizations, rather than the top level categories. I'll open this up and make some editorial changes.

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
- `curl` installed for making API requests

- `jq` installed for JSON parsing (optional, for formatting responses)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
- `jq` installed for JSON parsing (optional, for formatting responses)


## Authentication

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
## Authentication
## Set up OAT for Reports API


The Reports API requires an Organization Access Token (OAT). OATs are

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Move into pre-reqs to replace curl/jq prereqs

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Specifically some guidance around having available OATs, since some orgs have limitations; they need an open OAT slot to create a new one (if I'm understanding correctly)

org-scoped tokens designed for machine-to-machine access, making them
suitable for automated report retrieval workflows. Personal Access Tokens
(PATs) are not supported.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

turn into tip call out in prereqs


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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
## List available report types
## List reports


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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
Discover which report types and cadences are available for your organization.
You can fetch report types and their cadences on a per-organization basis. For example, you can fetch all available reports to your organization, or you can fetch a scoped set of reports by time interval.


```console

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
```console
### List all available reports
```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:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Per style guide, let's make this a complete sentence. For example:

Suggested change
Example response:
An example response will describe the report types and cadence. This response tells you that your organization has usage pull reports set to a daily cadence.


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

Each entry represents a distinct combination of report type and cadence. Use

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
Each entry represents a distinct combination of report type and cadence. Use
Each entry represents a distinct combination of report type and cadence. If you have more report types or different cadences configured, you can find that information here. Use

these values in subsequent calls.

## List reports

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
## List reports
### List reports by type and cadence


List available reports for a given type and cadence. Reports are returned in

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
List available reports for a given type and cadence. Reports are returned in
Based off the response to the list available reports query, you can list reports by type and cadence. Reports are returned in

reverse chronological order (most recent first).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
reverse chronological order (most recent first).
reverse chronological order so the most recent are listed first.


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

Example response:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Add some additional explanation in complete sentence form, per style guide


```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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
## Download a report
## Download reports

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

From a ToC POV, we want these specific actions to be nested and balanced for better visibility. We should add a sentence at minimum that describes why it's best practice to download a report, what you might use it for, and generalized information that's scattered in the below h3s. for example, this would be the place we say reports are downloaded as CSVs.


Download the CSV file for a specific date. The API responds with a `302`

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
Download the CSV file for a specific date. The API responds with a `302`
### Download specific reports
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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Super happy you included a troubleshooting section!


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