# Docker AI Governance API

HTTP API reference for managing Docker AI Governance policies and rules programmatically.

- **Version**: `1`
- **Base URL**: `https://hub.docker.com/v2`

- **OpenAPI specification**: [`api.yaml`](https://docs.docker.com/reference/api/ai-governance/api.yaml)

HTTP+JSON API for managing Docker governance policies and rules.

**Resource model.** An organization owns one or more policies. Each policy
contains a list of rules grouped into a single domain: either `network` or
`filesystem`. A policy's domain is derived from its rule actions; mixing
domains within a single policy is not permitted.

**Lifecycle.** Create a policy with CreatePolicy, then add rules with
CreateRule. Rules can be updated in place with UpdateRule or removed with
DeleteRule. Deleting all rules does not delete the policy itself.

**Rule evaluation.** All rules in a policy are tested against every request.
`deny` always wins: if any rule matches with `decision: deny`, the request
is denied regardless of any `allow` rules.

**Enforcement.** Organization policies take precedence over local sandbox
policies and cannot be overridden by individual users.

**Propagation.** Policy changes take up to five minutes to reach developer
machines after being written.

See https://docs.docker.com/ai/sandboxes/governance/ for product
documentation.



## Authentication


**`bearerAuth`** — type: `http`, scheme: `bearer`, bearer format: `JWT`

Short-lived JWT obtained by exchanging Docker Hub credentials at
`POST https://hub.docker.com/v2/users/login`. Pass the JWT in the
`Authorization: Bearer <token>` header. Tokens expire after a short
period; request a fresh one when you receive a `401`.

The `password` field of the login request accepts any of the following
credential types:

| Type | Format | Notes |
|------|--------|-------|
| Password | Plain text | Your Docker Hub account password. |
| Personal Access Token (PAT) | `dckr_pat_*` | Recommended over passwords. Create one under Account Settings → Security. |
| Organization Access Token (OAT) | `dckr_oat_*` | Scoped to an organization. Create one under Organization Settings → Access Tokens. |

PAT and OAT strings can't be used directly as a bearer token. They must
be exchanged at the login endpoint first.

See [Docker Hub authentication](https://docs.docker.com/reference/api/hub/latest/#tag/authentication-api/operation/AuthCreateAccessToken)
for full details.


## Policies

Policy lifecycle management
### `GET` `/orgs/{org_name}/governance/policies`

**List policies**

Returns a shallow summary of all policies for the org. The rule set is not included; use GetPolicy to fetch the full object.

**Parameters**

- `org_name` (path, string, required) — Docker Hub organization name.

**Responses**


`200` — Array of policy summaries. Rule sets are not included; use GetPolicy to fetch a full policy.



```json
[
  {
    "created_at": "2026-04-22T00:00:00Z",
    "id": "pol_06evsmp24r1pg71cm8500546pkbn",
    "name": "Security Research — hardened",
    "org": "my-org",
    "scope": {
      "profiles": [
        "security"
      ]
    },
    "type": "allowlist_v0",
    "updated_at": "2026-04-22T00:00:00Z"
  }
]
```


`401` — Missing or invalid credentials

Schema: `Error`

```json
{
  "error": {
    "code": "unauthenticated",
    "message": "unauthenticated"
  }
}
```


`403` — Caller lacks the required permission for this org, or the org is not entitled to use governance.

Schema: `Error`

```json
{
  "error": {
    "code": "permission_denied",
    "message": "permission denied"
  }
}
```


`500` — Internal server error

Schema: `Error`

```json
{
  "error": {
    "code": "internal",
    "message": "internal error"
  }
}
```



### `POST` `/orgs/{org_name}/governance/policies`

**Create policy**

Creates a new policy with an empty rule set. Rules are added separately via the rules sub-resource.

**Parameters**

- `org_name` (path, string, required) — Docker Hub organization name.

**Request body** — Policy name and optional scope.
Content type: `application/json`

Schema: `CreatePolicyRequest`

```json
{
  "name": "Security Research — hardened",
  "scope": {
    "profiles": [
      "security"
    ]
  }
}
```

**Responses**


`201` — Policy created. Returns the new policy without its rule set.

Schema: `Policy`

```json
{
  "created_at": "2026-04-22T00:00:00Z",
  "id": "pol_06evsmp24r1pg71cm8500546pkbn",
  "name": "Security Research — hardened",
  "org": "my-org",
  "scope": {
    "profiles": [
      "security"
    ]
  },
  "updated_at": "2026-04-22T00:00:00Z"
}
```


`400` — Bad request

Schema: `Error`

```json
{
  "error": {
    "code": "invalid_argument",
    "message": "name is required"
  }
}
```


`401` — Missing or invalid credentials

Schema: `Error`

```json
{
  "error": {
    "code": "unauthenticated",
    "message": "unauthenticated"
  }
}
```


`403` — Caller lacks the required permission for this org, or the org is not entitled to use governance.

Schema: `Error`

```json
{
  "error": {
    "code": "permission_denied",
    "message": "permission denied"
  }
}
```


`409` — Conflict

Schema: `Error`

```json
{
  "error": {
    "code": "conflict",
    "message": "policy name already in use"
  }
}
```


`500` — Internal server error

Schema: `Error`

```json
{
  "error": {
    "code": "internal",
    "message": "internal error"
  }
}
```



### `GET` `/orgs/{org_name}/governance/policies/{policy_id}`

**Get policy**

Returns the full policy including its `allowlist_v0` rule set.
**Parameters**

- `org_name` (path, string, required) — Docker Hub organization name.
- `policy_id` (path, string, required) — Unique policy identifier.

**Responses**


`200` — Full policy including its `allowlist_v0` rule set.

Schema: `Policy`

```json
{
  "allowlist_v0": {
    "domain": "network",
    "rules": [
      {
        "actions": [
          "connect:tcp",
          "connect:udp"
        ],
        "decision": "allow",
        "id": "rule_06evsm9qjm1pdsk0a8nkfaxy7jna",
        "name": "allow research mirrors",
        "resources": [
          "research.mitre.org",
          "cve.mitre.org"
        ]
      }
    ]
  },
  "created_at": "2026-04-22T00:00:00Z",
  "id": "pol_06evsmp24r1pg71cm8500546pkbn",
  "name": "Security Research — hardened",
  "org": "my-org",
  "scope": {
    "profiles": [
      "security"
    ]
  },
  "updated_at": "2026-04-22T00:00:00Z"
}
```


`401` — Missing or invalid credentials

Schema: `Error`

```json
{
  "error": {
    "code": "unauthenticated",
    "message": "unauthenticated"
  }
}
```


`403` — Caller lacks the required permission for this org, or the org is not entitled to use governance.

Schema: `Error`

```json
{
  "error": {
    "code": "permission_denied",
    "message": "permission denied"
  }
}
```


`404` — Not found

Schema: `Error`

```json
{
  "error": {
    "code": "not_found",
    "message": "policy not found"
  }
}
```


`500` — Internal server error

Schema: `Error`

```json
{
  "error": {
    "code": "internal",
    "message": "internal error"
  }
}
```



## Rules

Rule management within an allowlist policy
### `POST` `/orgs/{org_name}/governance/policies/{policy_id}/rules`

**Create rule**

Adds a rule to the policy's rule set. All rules in a policy must share
the same domain (network or filesystem); mixing domains is rejected.

**Network** actions: `connect:tcp`, `connect:udp`. Resources are
hostnames (for example, `example.com`), wildcard subdomains (`*.example.com`
for one level, `**.example.com` for any depth), hostnames with an optional
port (for example, `example.com:443`), or CIDRs in IPv4 or IPv6 notation
(for example, `10.0.0.0/8` or `2001:db8::/32`).

**Filesystem** actions: `read`, `write`. Resources are paths (for example,
`/data`). Use `*` to match within a single path segment and `**` to match
recursively across segments (for example, `/data/**`).

Changes may take up to five minutes to reach developer machines.

**Parameters**

- `org_name` (path, string, required) — Docker Hub organization name.
- `policy_id` (path, string, required) — Unique policy identifier.

**Request body** — Rule definition including actions, resources, and decision.
Content type: `application/json`

Schema: `CreateRuleRequest`

```json
{
  "actions": [
    "read",
    "write"
  ],
  "decision": "allow",
  "name": "allow data directory",
  "resources": [
    "/data"
  ]
}
```

```json
{
  "actions": [
    "connect:tcp",
    "connect:udp"
  ],
  "decision": "allow",
  "name": "allow research mirrors",
  "resources": [
    "research.mitre.org",
    "cve.mitre.org"
  ]
}
```

**Responses**


`201` — Rule created and added to the policy's rule set.

Schema: `Rule`

```json
{
  "actions": [
    "read",
    "write"
  ],
  "decision": "allow",
  "id": "rule_07fwtnr0kn2qetl1b9olfbyz8kob",
  "name": "allow data directory",
  "resources": [
    "/data"
  ]
}
```

```json
{
  "actions": [
    "connect:tcp",
    "connect:udp"
  ],
  "decision": "allow",
  "id": "rule_06evsm9qjm1pdsk0a8nkfaxy7jna",
  "name": "allow research mirrors",
  "resources": [
    "research.mitre.org",
    "cve.mitre.org"
  ]
}
```


`400` — Bad request

Schema: `Error`

```json
{
  "error": {
    "code": "invalid_argument",
    "message": "name is required"
  }
}
```


`401` — Missing or invalid credentials

Schema: `Error`

```json
{
  "error": {
    "code": "unauthenticated",
    "message": "unauthenticated"
  }
}
```


`403` — Caller lacks the required permission for this org, or the org is not entitled to use governance.

Schema: `Error`

```json
{
  "error": {
    "code": "permission_denied",
    "message": "permission denied"
  }
}
```


`404` — Not found

Schema: `Error`

```json
{
  "error": {
    "code": "not_found",
    "message": "policy not found"
  }
}
```


`500` — Internal server error

Schema: `Error`

```json
{
  "error": {
    "code": "internal",
    "message": "internal error"
  }
}
```



### `PATCH` `/orgs/{org_name}/governance/policies/{policy_id}/rules/{rule_id}`

**Update rule**

Partially updates a rule using JSON Merge Patch semantics (RFC 7396).
Only fields present in the request body are updated; absent fields are
left unchanged. Returns the rule in both its old and new states.

Changing `actions` across domains (for example, from network actions to
filesystem actions) is rejected. Changes may take up to five minutes to
reach developer machines.

**Parameters**

- `org_name` (path, string, required) — Docker Hub organization name.
- `policy_id` (path, string, required) — Unique policy identifier.
- `rule_id` (path, string, required) — Unique rule identifier within the policy.

**Request body** — Fields to update. Absent fields are left unchanged.
Content type: `application/merge-patch+json`

Schema: `UpdateRuleRequest`

```json
{
  "resources": [
    "research.mitre.org"
  ]
}
```

**Responses**


`200` — Rule updated, returns old and new states.

Schema: `UpdateRuleResponse`

```json
{
  "new": {
    "actions": [
      "connect:tcp",
      "connect:udp"
    ],
    "decision": "allow",
    "id": "rule_06evsm9qjm1pdsk0a8nkfaxy7jna",
    "name": "allow research mirrors",
    "resources": [
      "research.mitre.org"
    ]
  },
  "old": {
    "actions": [
      "connect:tcp",
      "connect:udp"
    ],
    "decision": "allow",
    "id": "rule_06evsm9qjm1pdsk0a8nkfaxy7jna",
    "name": "allow research mirrors",
    "resources": [
      "research.mitre.org",
      "cve.mitre.org"
    ]
  }
}
```


`400` — Bad request

Schema: `Error`

```json
{
  "error": {
    "code": "invalid_argument",
    "message": "name is required"
  }
}
```


`401` — Missing or invalid credentials

Schema: `Error`

```json
{
  "error": {
    "code": "unauthenticated",
    "message": "unauthenticated"
  }
}
```


`403` — Caller lacks the required permission for this org, or the org is not entitled to use governance.

Schema: `Error`

```json
{
  "error": {
    "code": "permission_denied",
    "message": "permission denied"
  }
}
```


`404` — Not found

Schema: `Error`

```json
{
  "error": {
    "code": "not_found",
    "message": "policy not found"
  }
}
```


`500` — Internal server error

Schema: `Error`

```json
{
  "error": {
    "code": "internal",
    "message": "internal error"
  }
}
```



### `DELETE` `/orgs/{org_name}/governance/policies/{policy_id}/rules/{rule_id}`

**Delete rule**

Deletes a rule from the policy. Returns the deleted rule. Changes may
take up to five minutes to reach developer machines.

**Parameters**

- `org_name` (path, string, required) — Docker Hub organization name.
- `policy_id` (path, string, required) — Unique policy identifier.
- `rule_id` (path, string, required) — Unique rule identifier within the policy.

**Responses**


`200` — Rule deleted, returns the deleted rule.

Schema: `DeleteRuleResponse`

```json
{
  "deleted": {
    "actions": [
      "connect:tcp",
      "connect:udp"
    ],
    "decision": "allow",
    "id": "rule_06evsm9qjm1pdsk0a8nkfaxy7jna",
    "name": "allow research mirrors",
    "resources": [
      "research.mitre.org",
      "cve.mitre.org"
    ]
  }
}
```


`401` — Missing or invalid credentials

Schema: `Error`

```json
{
  "error": {
    "code": "unauthenticated",
    "message": "unauthenticated"
  }
}
```


`403` — Caller lacks the required permission for this org, or the org is not entitled to use governance.

Schema: `Error`

```json
{
  "error": {
    "code": "permission_denied",
    "message": "permission denied"
  }
}
```


`404` — Not found

Schema: `Error`

```json
{
  "error": {
    "code": "not_found",
    "message": "policy not found"
  }
}
```


`500` — Internal server error

Schema: `Error`

```json
{
  "error": {
    "code": "internal",
    "message": "internal error"
  }
}
```



## Schemas


### `AllowlistV0`

Network or filesystem allowlist containing a list of rules. Present on
Policy when `PolicySummary.type` is `allowlist_v0`; omitted when the
policy has no rules yet. All rules in an allowlist share the same domain.
All rules are evaluated on every request: `deny` always wins over `allow`.


| Property | Type | Required | Description |
| -------- | ---- | -------- | ----------- |
| `domain` | `string` | no | The access-control domain shared by all rules in this allowlist. Derived from rule actions: network actions (`connect:tcp`, `connect:udp`) produce `network`; filesystem actions (`read`, `write`) produce `filesystem`. Present when `rules` is non-empty; absent when the allowlist has no rules. |
| `rules` | `array<``Rule``>` | yes |  |


### `CreatePolicyRequest`

Fields required to create a new policy.


| Property | Type | Required | Description |
| -------- | ---- | -------- | ----------- |
| `name` | `string` | yes | Policy name, unique within the organization. |
| `scope` | `Scope` | no |  |


### `CreateRuleRequest`

Fields required to create a new rule within a policy's rule set.


| Property | Type | Required | Description |
| -------- | ---- | -------- | ----------- |
| `actions` | `RuleActions` | yes |  |
| `decision` | `RuleDecision` | yes |  |
| `name` | `string` | yes | Human-readable label for the rule. |
| `resources` | `RuleResources` | yes |  |


### `DeleteRuleResponse`

The deleted rule.


| Property | Type | Required | Description |
| -------- | ---- | -------- | ----------- |
| `deleted` | `Rule` | yes |  |


### `Error`

Error envelope returned on all non-2xx responses.


| Property | Type | Required | Description |
| -------- | ---- | -------- | ----------- |
| `error` | `object` | yes | Error detail. |


### `Policy`

Full policy representation including the allowlist rule set.


| Property | Type | Required | Description |
| -------- | ---- | -------- | ----------- |
| `allowlist_v0` | `AllowlistV0` | no |  |
| `created_at` | `string` | yes |  |
| `id` | `string` | yes |  |
| `name` | `string` | yes | Human-readable label, unique within the organization. |
| `org` | `string` | yes |  |
| `scope` | `Scope` | yes |  |
| `updated_at` | `string` | yes |  |


### `PolicySummary`

Shallow policy representation returned by ListPolicies. Excludes the rule set.


| Property | Type | Required | Description |
| -------- | ---- | -------- | ----------- |
| `created_at` | `string` | yes |  |
| `id` | `string` | yes |  |
| `name` | `string` | yes | Human-readable label, unique within the organization. |
| `org` | `string` | yes |  |
| `scope` | `Scope` | yes |  |
| `type` | `string` | yes | Identifies the rule-set format. Always `allowlist_v0`, corresponding to the `allowlist_v0` property on the full Policy object. |
| `updated_at` | `string` | yes |  |


### `Rule`

A single allow or deny rule within an allowlist policy.


| Property | Type | Required | Description |
| -------- | ---- | -------- | ----------- |
| `actions` | `RuleActions` | yes |  |
| `decision` | `RuleDecision` | yes |  |
| `id` | `string` | yes |  |
| `name` | `string` | yes | Human-readable label for the rule. |
| `resources` | `RuleResources` | yes |  |


### `RuleActions`

Network actions: `connect:tcp`, `connect:udp`. Filesystem actions: `read`, `write`. All actions in a rule must belong to the same domain; mixing network and filesystem actions in one rule is rejected.


### `RuleDecision`

Outcome applied when this rule matches a request. `deny` always wins: if any rule in the policy matches with `decision: deny`, the request is denied even if other rules match with `decision: allow`.

Enum: `allow`, `deny`

### `RuleResources`

Network domain: hostnames (for example, `example.com`), wildcard subdomains (`*.example.com` or `**.example.com`), hostnames with port (for example, `example.com:443`), or CIDRs in IPv4 or IPv6 notation (for example, `10.0.0.0/8` or `2001:db8::/32`). Filesystem domain: paths (for example, `/data`); `*` matches within one path segment, `**` matches recursively (for example, `/data/**`).


### `Scope`

Restricts the policy to specific profiles or teams. Empty or absent lists mean the policy applies org-wide.


| Property | Type | Required | Description |
| -------- | ---- | -------- | ----------- |
| `profiles` | `array<``string``>` | no |  |
| `teams` | `array<``string``>` | no |  |


### `UpdateRuleRequest`

JSON Merge Patch (RFC 7396). Only present fields are updated.


| Property | Type | Required | Description |
| -------- | ---- | -------- | ----------- |
| `actions` | `RuleActions` | no |  |
| `decision` | `RuleDecision` | no |  |
| `name` | `string` | no | Human-readable label for the rule. |
| `resources` | `RuleResources` | no |  |


### `UpdateRuleResponse`

The rule state before and after the update.


| Property | Type | Required | Description |
| -------- | ---- | -------- | ----------- |
| `new` | `Rule` | yes |  |
| `old` | `Rule` | yes |  |

