Harbor REST API v2
Base: /api/v2.0. Latest stable: Harbor v2.15.1 (May 2026). API spec: Swagger 2.0 at api/v2.0/swagger.yaml. Built-in Swagger UI: https://<harbor>/devcenter-api-2.0.
Authentication
| Method |
Header / Usage |
Use Case |
| Basic Auth |
-u username:password |
Direct admin/developer API access |
| Bearer Token |
Authorization: Bearer <token> |
Obtained from /service/token per Docker Registry v2 spec |
| Robot Account |
-u robot$<prefix><name>:<secret> |
Automated CI/CD with scoped permissions |
| OIDC ID Token |
Authorization: Bearer <oidc_id_token> |
OIDC-authenticated users (basic auth not supported for OIDC) |
Bearer Token Flow
# Get token for push/pull access to a repo
TOKEN=$(curl -s -u "username:password" \
"https://harbor.example.com/service/token?service=harbor-registry&scope=repository:project/repo:pull,push" \
| jq -r '.token')
# Use for registry operations
curl -H "Authorization: Bearer $TOKEN" https://harbor.example.com/v2/_catalog
Robot Account Notes
- Secret shown only once at creation — Harbor does not store it
- Username format:
robot$<prefix><account_name>
- System-level (v2.2.0+) or project-level scope
- Permissions: granular RBAC (push, pull, create, read, delete, list, etc.)
Key Endpoints
Health & Status
| Method |
Endpoint |
Purpose |
| GET |
/health |
Component health (no auth) |
| GET |
/statistics |
Project & repo statistics |
| GET |
/search?q=<query> |
Search projects, repos, helm charts |
Project Management
| Method |
Endpoint |
Purpose |
| GET |
/projects |
List projects (filter: name, public, owner) |
| POST |
/projects |
Create project |
| HEAD |
/projects |
Check project name exists |
| GET |
/projects/{name_or_id} |
Get project |
| PUT |
/projects/{name_or_id} |
Update project |
| DELETE |
/projects/{name_or_id} |
Delete project |
| GET |
/projects/{name_or_id}/_deletable |
Check if deletable |
| GET |
/projects/{name_or_id}/summary |
Project summary |
| GET |
/projects/{name_or_id}/metadatas |
List metadata |
| POST |
/projects/{name_or_id}/metadatas |
Add metadata |
| GET/PUT/DELETE |
/projects/{name_or_id}/metadatas/{meta_name} |
CRUD metadata entry |
| GET |
/projects/{name_or_id}/members |
List members |
| POST |
/projects/{name_or_id}/members |
Add member |
| GET/PUT/DELETE |
/projects/{name_or_id}/members/{mid} |
CRUD member |
Repository Management
| Method |
Endpoint |
Purpose |
| GET |
/repositories |
List all authorized repos |
| GET |
/projects/{project}/repositories |
List repos in project |
| GET |
/projects/{project}/repositories/{repo} |
Get repo |
| PUT |
/projects/{project}/repositories/{repo} |
Update repo description |
| DELETE |
/projects/{project}/repositories/{repo} |
Delete repo |
Artifact Management
| Method |
Endpoint |
Purpose |
| GET |
/projects/{proj}/repositories/{repo}/artifacts |
List artifacts (?q=tags=*, labels, etc.) |
| POST |
/projects/{proj}/repositories/{repo}/artifacts |
Copy artifact |
| GET |
/projects/{proj}/repositories/{repo}/artifacts/{ref} |
Get artifact by digest or tag |
| DELETE |
/projects/{proj}/repositories/{repo}/artifacts/{ref} |
Delete artifact |
| PUT |
/projects/{proj}/repositories/{repo}/artifacts/{ref}/add-label |
Add label |
| DELETE |
/projects/{proj}/repositories/{repo}/artifacts/{ref}/labels/{label_id} |
Remove label |
| GET |
/projects/{proj}/repositories/{repo}/artifacts/{ref}/tags |
List tags |
| POST |
/projects/{proj}/repositories/{repo}/artifacts/{ref}/tags |
Create tag |
| DELETE |
/projects/{proj}/repositories/{repo}/artifacts/{ref}/tags/{tag} |
Delete tag |
Vulnerability Scanning
| Method |
Endpoint |
Purpose |
| POST |
/projects/{proj}/repositories/{repo}/artifacts/{ref}/scan |
Trigger scan |
| POST |
/projects/{proj}/repositories/{repo}/artifacts/{ref}/scan/stop |
Stop scan |
| GET |
/scanners |
List scanners |
| GET |
/scanners/{id} |
Get scanner metadata |
| POST |
/scanners/ping |
Ping scanner adapter |
| GET |
/projects/{proj}/repositories/{repo}/artifacts/{ref}/scan/{report_id} |
Get scan report |
Robot Accounts
| Method |
Endpoint |
Purpose |
| GET |
/robots |
List robot accounts |
| POST |
/robots |
Create robot account |
| GET |
/robots/{id} |
Get robot |
| PUT |
/robots/{id} |
Update robot |
| DELETE |
/robots/{id} |
Delete robot |
| PATCH |
/robots/{id} |
Refresh robot secret |
Replication
| Method |
Endpoint |
Purpose |
| GET |
/replication/policies |
List policies |
| POST |
/replication/policies |
Create policy |
| GET/PUT/DELETE |
/replication/policies/{id} |
CRUD policy |
| GET |
/replication/executions |
List executions |
| POST |
/replication/executions |
Start replication |
| GET |
/replication/executions/{id} |
Get execution status |
| GET |
/replication/executions/{id}/tasks |
List execution tasks |
| GET |
/registries |
List registries |
| POST |
/registries |
Create registry endpoint |
| GET/PUT/DELETE |
/registries/{id} |
CRUD registry |
| POST |
/registries/ping |
Ping registry endpoint |
Garbage Collection
| Method |
Endpoint |
Purpose |
| GET |
/system/gc |
List GC schedules |
| POST |
/system/gc |
Create GC schedule |
| GET |
/system/gc/{id} |
Get GC job |
| GET |
/system/gc/{id}/log |
Get GC log |
OIDC / LDAP
| Method |
Endpoint |
Purpose |
| POST |
/ldap/ping |
Ping LDAP |
| GET |
/ldap/users/search |
Search LDAP users |
| POST |
/ldap/users/import |
Import LDAP users |
| GET |
/ldap/groups/search |
Search LDAP groups |
| POST |
/system/oidc/ping |
Ping OIDC provider |
| GET |
/configurations |
Get system config (auth_mode, oidc, ldap) |
| PUT |
/configurations |
Update system config |
System & Admin
| Method |
Endpoint |
Purpose |
| GET |
/systeminfo |
System info |
| GET |
/systeminfo/volumes |
Storage volume info |
| GET |
/internalconfig |
Internal config (admin only) |
| GET |
/labels |
List labels |
| POST |
/labels |
Create label |
| GET/PUT/DELETE |
/labels/{id} |
CRUD label |
| GET |
/usergroups |
List user groups |
| POST |
/usergroups |
Create user group |
| GET/PUT/DELETE |
/usergroups/{id} |
CRUD user group |
| GET |
/preheat/policies |
List preheat policies |
| POST |
/preheat/policies |
Create preheat policy |
| GET |
/preheat/instances |
List preheat instances |
| POST |
/preheat/instances |
Create preheat instance |
| GET |
/audit-logs |
List audit logs |
| GET |
/quota |
List storage quotas |
Examples
# Create a project
curl -X POST https://harbor.example.com/api/v2.0/projects \
-u "admin:Harbor12345" \
-H "Content-Type: application/json" \
-d '{"project_name": "myapp", "public": false, "storage_limit": -1}'
# Create a robot account (system-level)
curl -X POST https://harbor.example.com/api/v2.0/robots \
-u "admin:Harbor12345" \
-H "Content-Type: application/json" \
-d '{
"name": "ci-deploy",
"description": "CI/CD deployment robot",
"level": "system",
"permissions": [{
"kind": "project",
"namespace": "myapp",
"access": [
{"resource": "repository", "action": "pull"},
{"resource": "repository", "action": "push"}
]
}]
}'
# Trigger artifact scan
curl -X POST "https://harbor.example.com/api/v2.0/projects/myapp/repositories/nginx/artifacts/latest/scan" \
-u "admin:Harbor12345"
# Create a replication rule
curl -X POST https://harbor.example.com/api/v2.0/replication/policies \
-u "admin:Harbor12345" \
-H "Content-Type: application/json" \
-d '{
"name": "backup-to-dr",
"description": "Replicate to DR site",
"trigger": {"type": "event_based"},
"dest_registry": {"id": 2},
"filters": [{"type": "name", "value": "myapp/**"}],
"deletion": true,
"override": true
}'
# Search across Harbor
curl -s "https://harbor.example.com/api/v2.0/search?q=nginx" \
-u "admin:Harbor12345"
# Trigger garbage collection
curl -X POST https://harbor.example.com/api/v2.0/system/gc \
-u "admin:Harbor12345" \
-H "Content-Type: application/json" \
-d '{"schedule": {"type": "Weekly", "weekday": 0, "offtime": 0}}'
Common Mistakes
- Robot secret not saved — Secret is only returned on creation. Store it immediately.
- API version path — Always use
/api/v2.0/, not /api/ (v1.x legacy path).
- OIDC users can't use basic auth — Must use OIDC ID token as Bearer token.
- Robot tokens auto-expire — Set
duration in days on creation (default: no expiry).
- Scan reports deleted on v2.2 upgrade — Schema migration clears old scan data. Re-scan after upgrade.
- Bearer token scope — Token is scoped to the
scope param in the /service/token request. Use repository:*:pull for read-only, repository:*:pull,push for write.
1---2name: harbor-api3description: Use when working with the Harbor REST API v2 — project management, artifact operations, robot accounts, replication, vulnerability scanning, OIDC/LDAP config, garbage collection, and general API automation with curl.4---56# Harbor REST API v278Base: `/api/v2.0`. Latest stable: **Harbor v2.15.1** (May 2026). API spec: Swagger 2.0 at `api/v2.0/swagger.yaml`. Built-in Swagger UI: `https://<harbor>/devcenter-api-2.0`.910## Authentication1112| Method | Header / Usage | Use Case |13|--------|---------------|----------|14| Basic Auth | `-u username:password` | Direct admin/developer API access |15| Bearer Token | `Authorization: Bearer <token>` | Obtained from `/service/token` per Docker Registry v2 spec |16| Robot Account | `-u robot$<prefix><name>:<secret>` | Automated CI/CD with scoped permissions |17| OIDC ID Token | `Authorization: Bearer <oidc_id_token>` | OIDC-authenticated users (basic auth not supported for OIDC) |1819### Bearer Token Flow20```bash21# Get token for push/pull access to a repo22TOKEN=$(curl -s -u "username:password" \23 "https://harbor.example.com/service/token?service=harbor-registry&scope=repository:project/repo:pull,push" \24 | jq -r '.token')2526# Use for registry operations27curl -H "Authorization: Bearer $TOKEN" https://harbor.example.com/v2/_catalog28```2930### Robot Account Notes31- Secret shown **only once** at creation — Harbor does not store it32- Username format: `robot$<prefix><account_name>`33- System-level (v2.2.0+) or project-level scope34- Permissions: granular RBAC (push, pull, create, read, delete, list, etc.)3536## Key Endpoints3738### Health & Status3940| Method | Endpoint | Purpose |41|--------|----------|---------|42| GET | `/health` | Component health (no auth) |43| GET | `/statistics` | Project & repo statistics |44| GET | `/search?q=<query>` | Search projects, repos, helm charts |4546### Project Management4748| Method | Endpoint | Purpose |49|--------|----------|---------|50| GET | `/projects` | List projects (filter: name, public, owner) |51| POST | `/projects` | Create project |52| HEAD | `/projects` | Check project name exists |53| GET | `/projects/{name_or_id}` | Get project |54| PUT | `/projects/{name_or_id}` | Update project |55| DELETE | `/projects/{name_or_id}` | Delete project |56| GET | `/projects/{name_or_id}/_deletable` | Check if deletable |57| GET | `/projects/{name_or_id}/summary` | Project summary |58| GET | `/projects/{name_or_id}/metadatas` | List metadata |59| POST | `/projects/{name_or_id}/metadatas` | Add metadata |60| GET/PUT/DELETE | `/projects/{name_or_id}/metadatas/{meta_name}` | CRUD metadata entry |61| GET | `/projects/{name_or_id}/members` | List members |62| POST | `/projects/{name_or_id}/members` | Add member |63| GET/PUT/DELETE | `/projects/{name_or_id}/members/{mid}` | CRUD member |6465### Repository Management6667| Method | Endpoint | Purpose |68|--------|----------|---------|69| GET | `/repositories` | List all authorized repos |70| GET | `/projects/{project}/repositories` | List repos in project |71| GET | `/projects/{project}/repositories/{repo}` | Get repo |72| PUT | `/projects/{project}/repositories/{repo}` | Update repo description |73| DELETE | `/projects/{project}/repositories/{repo}` | Delete repo |7475### Artifact Management7677| Method | Endpoint | Purpose |78|--------|----------|---------|79| GET | `/projects/{proj}/repositories/{repo}/artifacts` | List artifacts (`?q=tags=*`, labels, etc.) |80| POST | `/projects/{proj}/repositories/{repo}/artifacts` | Copy artifact |81| GET | `/projects/{proj}/repositories/{repo}/artifacts/{ref}` | Get artifact by digest or tag |82| DELETE | `/projects/{proj}/repositories/{repo}/artifacts/{ref}` | Delete artifact |83| PUT | `/projects/{proj}/repositories/{repo}/artifacts/{ref}/add-label` | Add label |84| DELETE | `/projects/{proj}/repositories/{repo}/artifacts/{ref}/labels/{label_id}` | Remove label |85| GET | `/projects/{proj}/repositories/{repo}/artifacts/{ref}/tags` | List tags |86| POST | `/projects/{proj}/repositories/{repo}/artifacts/{ref}/tags` | Create tag |87| DELETE | `/projects/{proj}/repositories/{repo}/artifacts/{ref}/tags/{tag}` | Delete tag |8889### Vulnerability Scanning9091| Method | Endpoint | Purpose |92|--------|----------|---------|93| POST | `/projects/{proj}/repositories/{repo}/artifacts/{ref}/scan` | Trigger scan |94| POST | `/projects/{proj}/repositories/{repo}/artifacts/{ref}/scan/stop` | Stop scan |95| GET | `/scanners` | List scanners |96| GET | `/scanners/{id}` | Get scanner metadata |97| POST | `/scanners/ping` | Ping scanner adapter |98| GET | `/projects/{proj}/repositories/{repo}/artifacts/{ref}/scan/{report_id}` | Get scan report |99100### Robot Accounts101102| Method | Endpoint | Purpose |103|--------|----------|---------|104| GET | `/robots` | List robot accounts |105| POST | `/robots` | Create robot account |106| GET | `/robots/{id}` | Get robot |107| PUT | `/robots/{id}` | Update robot |108| DELETE | `/robots/{id}` | Delete robot |109| PATCH | `/robots/{id}` | Refresh robot secret |110111### Replication112113| Method | Endpoint | Purpose |114|--------|----------|---------|115| GET | `/replication/policies` | List policies |116| POST | `/replication/policies` | Create policy |117| GET/PUT/DELETE | `/replication/policies/{id}` | CRUD policy |118| GET | `/replication/executions` | List executions |119| POST | `/replication/executions` | Start replication |120| GET | `/replication/executions/{id}` | Get execution status |121| GET | `/replication/executions/{id}/tasks` | List execution tasks |122| GET | `/registries` | List registries |123| POST | `/registries` | Create registry endpoint |124| GET/PUT/DELETE | `/registries/{id}` | CRUD registry |125| POST | `/registries/ping` | Ping registry endpoint |126127### Garbage Collection128129| Method | Endpoint | Purpose |130|--------|----------|---------|131| GET | `/system/gc` | List GC schedules |132| POST | `/system/gc` | Create GC schedule |133| GET | `/system/gc/{id}` | Get GC job |134| GET | `/system/gc/{id}/log` | Get GC log |135136### OIDC / LDAP137138| Method | Endpoint | Purpose |139|--------|----------|---------|140| POST | `/ldap/ping` | Ping LDAP |141| GET | `/ldap/users/search` | Search LDAP users |142| POST | `/ldap/users/import` | Import LDAP users |143| GET | `/ldap/groups/search` | Search LDAP groups |144| POST | `/system/oidc/ping` | Ping OIDC provider |145| GET | `/configurations` | Get system config (auth_mode, oidc, ldap) |146| PUT | `/configurations` | Update system config |147148### System & Admin149150| Method | Endpoint | Purpose |151|--------|----------|---------|152| GET | `/systeminfo` | System info |153| GET | `/systeminfo/volumes` | Storage volume info |154| GET | `/internalconfig` | Internal config (admin only) |155| GET | `/labels` | List labels |156| POST | `/labels` | Create label |157| GET/PUT/DELETE | `/labels/{id}` | CRUD label |158| GET | `/usergroups` | List user groups |159| POST | `/usergroups` | Create user group |160| GET/PUT/DELETE | `/usergroups/{id}` | CRUD user group |161| GET | `/preheat/policies` | List preheat policies |162| POST | `/preheat/policies` | Create preheat policy |163| GET | `/preheat/instances` | List preheat instances |164| POST | `/preheat/instances` | Create preheat instance |165| GET | `/audit-logs` | List audit logs |166| GET | `/quota` | List storage quotas |167168## Examples169170```bash171# Create a project172curl -X POST https://harbor.example.com/api/v2.0/projects \173 -u "admin:Harbor12345" \174 -H "Content-Type: application/json" \175 -d '{"project_name": "myapp", "public": false, "storage_limit": -1}'176177# Create a robot account (system-level)178curl -X POST https://harbor.example.com/api/v2.0/robots \179 -u "admin:Harbor12345" \180 -H "Content-Type: application/json" \181 -d '{182 "name": "ci-deploy",183 "description": "CI/CD deployment robot",184 "level": "system",185 "permissions": [{186 "kind": "project",187 "namespace": "myapp",188 "access": [189 {"resource": "repository", "action": "pull"},190 {"resource": "repository", "action": "push"}191 ]192 }]193 }'194195# Trigger artifact scan196curl -X POST "https://harbor.example.com/api/v2.0/projects/myapp/repositories/nginx/artifacts/latest/scan" \197 -u "admin:Harbor12345"198199# Create a replication rule200curl -X POST https://harbor.example.com/api/v2.0/replication/policies \201 -u "admin:Harbor12345" \202 -H "Content-Type: application/json" \203 -d '{204 "name": "backup-to-dr",205 "description": "Replicate to DR site",206 "trigger": {"type": "event_based"},207 "dest_registry": {"id": 2},208 "filters": [{"type": "name", "value": "myapp/**"}],209 "deletion": true,210 "override": true211 }'212213# Search across Harbor214curl -s "https://harbor.example.com/api/v2.0/search?q=nginx" \215 -u "admin:Harbor12345"216217# Trigger garbage collection218curl -X POST https://harbor.example.com/api/v2.0/system/gc \219 -u "admin:Harbor12345" \220 -H "Content-Type: application/json" \221 -d '{"schedule": {"type": "Weekly", "weekday": 0, "offtime": 0}}'222```223224## Common Mistakes225226- **Robot secret not saved** — Secret is only returned on creation. Store it immediately.227- **API version path** — Always use `/api/v2.0/`, not `/api/` (v1.x legacy path).228- **OIDC users can't use basic auth** — Must use OIDC ID token as Bearer token.229- **Robot tokens auto-expire** — Set `duration` in days on creation (default: no expiry).230- **Scan reports deleted on v2.2 upgrade** — Schema migration clears old scan data. Re-scan after upgrade.231- **Bearer token scope** — Token is scoped to the `scope` param in the `/service/token` request. Use `repository:*:pull` for read-only, `repository:*:pull,push` for write.