Projects API
30 endpoints. Request and response schemas are described on the schemas page; the other tags are listed in the API index.
Endpoints
GET /api/v1/admin/projects/settings
Get project settings
Global admins only. self_create is the effective projects.self_create value: the stored setting, else the OPENARTIFACT_PROJECTS_SELF_CREATE / projects.selfCreate default.
Responses
| Status | Description | Body |
|---|---|---|
200 | Project settings | application/json: ProjectSettings |
403 | Admin access required | - |
PUT /api/v1/admin/projects/settings
Update project settings
Global admins only. Turning self_create on lets any human user create projects (and become their owner).
Request body (required)
application/json: ProjectSettings
Responses
| Status | Description | Body |
|---|---|---|
200 | Settings saved | application/json: ProjectSettings |
400 | Invalid request | application/json: Error |
403 | Admin access required | - |
GET /api/v1/projects
List projects
List the projects the caller holds a role in, each with my_role, repository_count, member_count (direct members), usage and quota (computed for the whole list with grouped queries); with all=true, every project (global administrators only, others get 403). can_create tells whether the caller may create a project (global admin, or any human user while the projects.self_create setting is on).
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
all | query | boolean | no | List every project instead of only the caller's own. Global administrators only. Default: false. |
q | query | string | no | Case-insensitive substring of the project name, slug or display name. |
Responses
| Status | Description | Body |
|---|---|---|
200 | List of projects | application/json: object |
400 | Invalid request, including a NUL byte in the URL or the body | application/json: Error |
403 | Forbidden | application/json: Error |
Fields of the 200 response (application/json):
| Field | Type | Required | Description |
|---|---|---|---|
can_create | boolean | no | - |
projects | array of ProjectListItem | no | - |
POST /api/v1/projects
Create project
Create a project. Global admins always may and can set the owner and the policy fields; any other human user may only while projects.self_create is on, becomes the owner, and gets the default policy (policy fields or owner in the body give 403). Tokens with scopes and deploy tokens cannot create projects.
Request body (required)
application/json: ProjectCreateRequest
Responses
| Status | Description | Body |
|---|---|---|
201 | Project created | application/json: Project |
400 | Invalid name, slug or policy field | - |
403 | Self-service project creation is off, the caller is not a human user, or a non-admin sent policy fields or an owner | - |
404 | Owner user not found | - |
409 | Project name or slug already taken | - |
GET /api/v1/projects/{project}
Get project
Get details of a specific project. Requires a role in the project (viewer or above) or global admin; a non-member gets 404.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
project | path | string | yes | - |
Responses
| Status | Description | Body |
|---|---|---|
200 | Project details | application/json: Project |
400 | Invalid request, including a NUL byte in the URL or the body | application/json: Error |
403 | Forbidden | application/json: Error |
404 | Project not found or the caller is not a member | - |
PATCH /api/v1/projects/{project}
Update project
Partially update a project: only the fields present in the body change. display_name and description need the owner role or global admin; the policy fields need global admin (403 otherwise).
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
project | path | string | yes | - |
Request body (required)
application/json: ProjectUpdateRequest
Responses
| Status | Description | Body |
|---|---|---|
200 | Project updated | application/json: Project |
400 | Invalid policy field | - |
403 | Not an owner, or a policy field sent by a non-admin | - |
404 | Project not found or the caller is not a member | - |
DELETE /api/v1/projects/{project}
Delete project
Delete a project. Requires the owner role or global admin.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
project | path | string | yes | - |
Responses
| Status | Description | Body |
|---|---|---|
204 | Project deleted | - |
400 | Invalid request, including a NUL byte in the URL or the body | application/json: Error |
403 | Not an owner | - |
404 | Project not found or the caller is not a member | - |
409 | Project still owns repositories, or it is the system project | - |
GET /api/v1/projects/{project}/activity
Project activity
Audit events of the project and of the repositories it owns (member, group, token, quota, policy and repository changes, plus events recorded against its repositories), newest first. Keyset paging only: follow next_cursor while has_more is true; no row is counted. Client addresses are not returned. Any member; a non-member gets 404.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
project | path | string | yes | - |
per_page | query | integer | no | Default: 25. Minimum: 1. Maximum: 100. |
cursor | query | string | no | Opaque next_cursor of the previous page; omit for the newest entries. |
actor | query | string | no | Case-insensitive substring of the actor name or actor id. |
action | query | string | no | Case-insensitive substring of the action name. |
Responses
| Status | Description | Body |
|---|---|---|
200 | One page of activity | application/json: ActivityPage |
400 | Malformed cursor | - |
403 | Forbidden | application/json: Error |
404 | Project not found or the caller is not a member | - |
GET /api/v1/projects/{project}/activity/export
Export project activity
Export the project's activity (same scope and visibility as GET /api/v1/projects/{project}/activity: project.token_* events only for maintainers and above, no client addresses) as JSONL or CSV, for any member. Streams the log as a download without counting rows: entries are read in keyset pages (newest first) and flushed after every page, so memory stays bounded however long the log is. The body is chunked (no Content-Length); if the server fails after the response started the connection is aborted rather than ended normally, so a truncated file is detectable. In CSV, cells starting with =, +, -, @, tab or CR are prefixed with ' to defuse spreadsheet formula injection. Fields: id, timestamp (RFC 3339, UTC), action, actor, actor_type, message, resource_type, resource_id, repository_id.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
project | path | string | yes | - |
format | query | string | no | jsonl (default): one JSON object per line. csv: header row plus one record per entry. One of: jsonl, csv. Default: jsonl. |
since | query | string | no | Only entries at or after this instant: RFC 3339 timestamp or YYYY-MM-DD (00:00 UTC). |
until | query | string | no | Only entries strictly before this instant (same forms as since); must be after since. |
actor | query | string | no | Case-insensitive substring of the actor name or actor id. |
action | query | string | no | Case-insensitive substring of the action name. |
Responses
| Status | Description | Body |
|---|---|---|
200 | Activity export stream Headers: Content-Disposition. | application/x-ndjson: string; text/csv: string |
400 | Unknown format, malformed since/until, or since not before until | - |
403 | Access denied | - |
404 | Project not found or the caller is not a member | - |
GET /api/v1/projects/{project}/cleanup-policies
List project cleanup policies
Default cleanup policies of the project. A project policy applies to every live hosted repository of the project that has no enabled policy of its own (a repository policy overrides the default). Any member.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
project | path | string | yes | - |
Responses
| Status | Description | Body |
|---|---|---|
200 | Policies | application/json: object |
400 | Invalid request, including a NUL byte in the URL or the body | application/json: Error |
403 | Forbidden | application/json: Error |
404 | Project not found or the caller is not a member | - |
Fields of the 200 response (application/json):
| Field | Type | Required | Description |
|---|---|---|---|
policies | array of CleanupPolicy | no | - |
POST /api/v1/projects/{project}/cleanup-policies
Create project cleanup policy
Owners and global admins. Same fields and validation as a repository cleanup policy.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
project | path | string | yes | - |
Request body (required)
application/json: object
| Field | Type | Required | Description |
|---|---|---|---|
enabled | boolean | no | - |
keep_last_n | integer | no | - |
keep_since_days | integer | no | - |
name | string | no | - |
name_pattern | string | no | - |
schedule_cron | string | no | - |
Responses
| Status | Description | Body |
|---|---|---|
201 | Created | application/json: CleanupPolicy |
400 | Invalid policy | - |
403 | Not an owner | - |
404 | Project not found or the caller is not a member | - |
PUT /api/v1/projects/{project}/cleanup-policies/{id}
Update project cleanup policy
Owners and global admins. Partial update.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
project | path | string | yes | - |
id | path | string (uuid) | yes | - |
Request body (required)
application/json: object
| Field | Type | Required | Description |
|---|---|---|---|
enabled | boolean | no | - |
keep_last_n | integer | no | - |
keep_since_days | integer | no | - |
name | string | no | - |
name_pattern | string | no | - |
schedule_cron | string | no | - |
Responses
| Status | Description | Body |
|---|---|---|
200 | Updated | application/json: CleanupPolicy |
400 | Invalid policy | - |
403 | Not an owner | - |
404 | Project or policy not found | - |
DELETE /api/v1/projects/{project}/cleanup-policies/{id}
Delete project cleanup policy
Owners and global admins.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
project | path | string | yes | - |
id | path | string (uuid) | yes | - |
Responses
| Status | Description | Body |
|---|---|---|
204 | Deleted | - |
400 | Invalid request, including a NUL byte in the URL or the body | application/json: Error |
403 | Not an owner | - |
404 | Project or policy not found | - |
POST /api/v1/projects/{project}/cleanup-policies/{id}/dry-run
Preview what a project default cleanup policy would remove
Owners and global admins. Expands the policy over the repositories a run would cover and lists, per repository, the rows a run would remove (capped at 500 each). Nothing is changed.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
project | path | string | yes | - |
id | path | string (uuid) | yes | - |
Responses
| Status | Description | Body |
|---|---|---|
200 | What a run would remove | application/json: ProjectCleanupPreview |
default | Error | application/json: Error |
GET /api/v1/projects/{project}/groups
List project groups
List groups attached to a project, with the role each group's members get. Requires a role in the project (viewer or above) or global admin; a non-member gets 404.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
project | path | string | yes | - |
Responses
| Status | Description | Body |
|---|---|---|
200 | List of project groups | application/json: object |
400 | Invalid request, including a NUL byte in the URL or the body | application/json: Error |
403 | Forbidden | application/json: Error |
404 | Project not found | - |
Fields of the 200 response (application/json):
| Field | Type | Required | Description |
|---|---|---|---|
groups | array of ProjectGroup | no | - |
PUT /api/v1/projects/{project}/groups/{group}
Attach or update project group
Attach a group with a role, or change the role of an attached group. Requires the owner or maintainer role or global admin (maintainers may only touch roles below maintainer); a viewer or developer gets 403, a non-member 404. Granting or changing the maintainer role needs the owner role.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
project | path | string | yes | - |
group | path | string | yes | Group ID or exact group name |
Request body (required)
application/json: ProjectGroupUpdateRequest
Responses
| Status | Description | Body |
|---|---|---|
200 | Group attached or updated | application/json: ProjectGroup |
400 | Invalid role | - |
403 | Not allowed to grant or change this role | - |
404 | Project or group not found | - |
DELETE /api/v1/projects/{project}/groups/{group}
Detach project group
Detach a group. Requires the owner or maintainer role or global admin (maintainers may only touch roles below maintainer); a viewer or developer gets 403, a non-member 404.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
project | path | string | yes | - |
group | path | string | yes | Group ID or exact group name |
Responses
| Status | Description | Body |
|---|---|---|
204 | Group detached | - |
400 | Invalid request, including a NUL byte in the URL or the body | application/json: Error |
403 | Not allowed to grant or change this role | - |
404 | Group not attached | - |
GET /api/v1/projects/{project}/members
List project members
List members of a project. Requires a role in the project (viewer or above) or global admin; a non-member gets 404.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
project | path | string | yes | - |
Responses
| Status | Description | Body |
|---|---|---|
200 | List of project members | application/json: object |
400 | Invalid request, including a NUL byte in the URL or the body | application/json: Error |
403 | Forbidden | application/json: Error |
404 | Project not found or the caller is not a member | - |
Fields of the 200 response (application/json):
| Field | Type | Required | Description |
|---|---|---|---|
members | array of ProjectMember | no | - |
POST /api/v1/projects/{project}/members
Add project member
Add a user (by user_id or username, exactly one) to a project; the role defaults to viewer. Requires the owner or maintainer role or global admin (maintainers may only touch roles below maintainer); a viewer or developer gets 403, a non-member 404.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
project | path | string | yes | - |
Request body (required)
application/json: ProjectMemberCreateRequest
Responses
| Status | Description | Body |
|---|---|---|
201 | Member added | application/json: ProjectMember |
400 | Invalid role | - |
403 | Not allowed to grant this role | - |
404 | Project or user not found | - |
409 | User is already a member | - |
PATCH /api/v1/projects/{project}/members/{user_id}
Update project member
Change a member's role. Requires the owner or maintainer role or global admin (maintainers may only touch roles below maintainer); a viewer or developer gets 403, a non-member 404. The recorded project owner cannot be demoted and the last owner cannot be demoted or removed (409).
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
project | path | string | yes | - |
user_id | path | string (uuid) | yes | - |
Request body (required)
application/json: ProjectMemberUpdateRequest
Responses
| Status | Description | Body |
|---|---|---|
200 | Member updated | application/json: ProjectMember |
400 | Invalid role | - |
403 | Not allowed to change this role | - |
404 | Project or member not found | - |
409 | Would remove or demote the recorded or last owner | - |
DELETE /api/v1/projects/{project}/members/{user_id}
Remove project member
Remove a member. Requires the owner or maintainer role or global admin (maintainers may only touch roles below maintainer); a viewer or developer gets 403, a non-member 404. The recorded project owner and the last owner cannot be removed (409).
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
project | path | string | yes | - |
user_id | path | string (uuid) | yes | - |
Responses
| Status | Description | Body |
|---|---|---|
204 | Member removed | - |
400 | Invalid request, including a NUL byte in the URL or the body | application/json: Error |
403 | Not allowed to change this role | - |
404 | Member not found | - |
409 | Would remove or demote the recorded or last owner | - |
GET /api/v1/projects/{project}/quota
Get project quota
The project's storage ceiling (0 = unlimited) and its live usage. Any member.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
project | path | string | yes | - |
Responses
| Status | Description | Body |
|---|---|---|
200 | Project quota | application/json: ProjectQuota |
400 | Invalid request, including a NUL byte in the URL or the body | application/json: Error |
403 | Forbidden | application/json: Error |
404 | Project not found or the caller is not a member | - |
PUT /api/v1/projects/{project}/quota
Set project quota
Global admins only: sets the ceiling over the sum of the project's repositories (0 = unlimited). An upload must fit both its repository's limit and the project's. Enabling a limit initialises the project counters from the repositories' usage. Omitted fields keep their value. Repository limits above the project limit are refused when set.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
project | path | string | yes | - |
Request body (required)
application/json: object
| Field | Type | Required | Description |
|---|---|---|---|
max_artifact_count | integer (int64) | no | Minimum: 0. |
max_size_bytes | integer (int64) | no | Minimum: 0. |
warn_threshold_percent | integer | no | Minimum: 0. Maximum: 100. |
Responses
| Status | Description | Body |
|---|---|---|
200 | Project quota | application/json: ProjectQuota |
400 | Invalid limits | - |
403 | Not a global admin | - |
404 | Project not found or the caller is not a member | - |
GET /api/v1/projects/{project}/repositories
List project repositories
List the live (not trashed) repositories of a project, newest first. Requires a role in the project (viewer or above) or global admin; a non-member gets 404.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
project | path | string | yes | - |
page | query | integer | no | Default: 1. Minimum: 1. |
limit | query | integer | no | Default: 25. Minimum: 1. Maximum: 100. |
Responses
| Status | Description | Body |
|---|---|---|
200 | A page of repositories | application/json: object |
400 | Invalid request, including a NUL byte in the URL or the body | application/json: Error |
403 | Forbidden | application/json: Error |
404 | Project not found or the caller is not a member | - |
Fields of the 200 response (application/json):
| Field | Type | Required | Description |
|---|---|---|---|
limit | integer | no | - |
page | integer | no | - |
repositories | array of Repository | no | - |
total | integer | no | - |
POST /api/v1/projects/{project}/repositories
Create a repository in a project
Create a repository owned by the project. Requires the maintainer or owner role in the project, or global admin; a non-member gets 404. The body is the one of POST /api/v1/repositories without project (the URL names it). For a caller who is not a global admin the project policy applies: format in allowed_formats (when set), repo_type in allowed_repo_types, name starting with repo_name_prefix (400 validation_failed), public only when allow_public_repos (403), member_repos readable by the caller (403) and the project below max_repositories (409 project_repository_limit).
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
project | path | string | yes | - |
Request body (required)
application/json: object
| Field | Type | Required | Description |
|---|---|---|---|
cache_ttl_seconds | integer | no | - |
description | string | no | - |
federated | boolean | no | Enable federation at creation. Only valid for hosted repositories of the formats raw, maven, npm, docker, helm, pypi, cargo, go and nuget (400 otherwise when true). |
format | string | yes | - |
immutable_releases | boolean | no | - |
max_stale_seconds | integer | no | - |
member_repos | array of string | no | - |
merge_proxy_versions | boolean | no | Group repositories only, administrators only (403 otherwise). Default false: hosted members win a package name and proxy versions of the same name are hidden. true merges proxy versions into the group. |
name | string | yes | - |
negative_cache_ttl_seconds | integer | no | - |
presign_downloads | boolean | no | Nullable. |
public | boolean | no | - |
repo_type | string | no | One of: hosted, proxy, group. |
sign_packages | boolean | no | Hosted rpm repositories only (400 otherwise when true). When true, uploaded RPMs are signed with the active GPG key; existing packages are not re-signed. |
trash_retention_days | integer | no | Nullable. |
upstream_password | string | no | - |
upstream_url | string | no | - |
upstream_username | string | no | - |
Responses
| Status | Description | Body |
|---|---|---|
201 | Repository created | application/json: Repository |
400 | Invalid request or a project policy violation (format, type, name prefix) | - |
403 | Role below maintainer, public repository not allowed, or a member repository the caller cannot read | - |
404 | Project not found or the caller is not a member | - |
409 | Name already taken, or the project reached max_repositories (project_repository_limit) | - |
POST /api/v1/projects/{project}/repositories/{name}/transfer
Transfer a repository to another project
Move a repository of {project} to the project named in the body. Requires the owner role in both projects (global admin holds both); a caller with no role in one of them gets 404 for it, a lower role 403. For a caller who is not a global admin the target project's policy applies as at creation (format, type, name prefix, public) and its max_repositories (409). Access of both projects' members changes immediately.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
project | path | string | yes | - |
name | path | string | yes | - |
Request body (required)
application/json: object
| Field | Type | Required | Description |
|---|---|---|---|
to_project | string | yes | - |
Responses
| Status | Description | Body |
|---|---|---|
200 | Repository transferred | application/json: Repository |
400 | Missing to_project, same project, or a target policy violation | - |
403 | Not an owner of the source or the target project, or the target forbids public repositories | - |
404 | Project or repository not found, or the caller has no role in a project | - |
409 | The target project reached max_repositories | - |
GET /api/v1/projects/{project}/tokens
List project tokens
List the active tokens of a project. Maintainers, owners and global admins see all tokens; other members only the ones they minted. A non-member gets 404.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
project | path | string | yes | - |
Responses
| Status | Description | Body |
|---|---|---|
200 | Project tokens | application/json: object |
400 | Invalid request, including a NUL byte in the URL or the body | application/json: Error |
403 | Forbidden | application/json: Error |
404 | Project not found or the caller is not a member | - |
Fields of the 200 response (application/json):
| Field | Type | Required | Description |
|---|---|---|---|
tokens | array of ProjectToken | no | - |
POST /api/v1/projects/{project}/tokens
Create project token
Mint a deploy token for CI. It belongs to a service account of the project: it can only use the repositories of this project (viewer: read, developer: read and write), never /api/v1/**, and is revoked when its creator leaves the project, is disabled or deleted. Requires a session (API tokens cannot mint). The role may not exceed the caller's own role. expires_at is required when the project limits token lifetime (token_max_ttl_days) and may not exceed it. At most 100 active tokens per project; names are unique among them. The secret is returned once.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
project | path | string | yes | - |
Request body (required)
application/json: ProjectTokenCreateRequest
Responses
| Status | Description | Body |
|---|---|---|
201 | Token created | application/json: ProjectTokenCreateResponse |
400 | Invalid name, role or expiry | - |
403 | Not a session, or the role exceeds the caller's own role | - |
404 | Project not found or the caller is not a member | - |
409 | Name already in use, or the project has 100 active tokens | - |
DELETE /api/v1/projects/{project}/tokens/{token_id}
Revoke project token
Revoke a project token; it stops working immediately. Maintainers, owners and global admins may revoke any token of the project, other members only their own (403 otherwise).
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
project | path | string | yes | - |
token_id | path | string (uuid) | yes | - |
Responses
| Status | Description | Body |
|---|---|---|
204 | Token revoked | - |
400 | Invalid request, including a NUL byte in the URL or the body | application/json: Error |
403 | Not allowed to revoke this token | - |
404 | Project or token not found | - |
GET /api/v1/projects/{project}/usage
Project usage
Storage usage of a project: the sum of its repositories' counters, the project quota and one line per live repository, largest first. Every repository of a hosted type is metered (quota_enforced); proxy and group repositories hold no uploaded packages. Any member; a non-member gets 404. project.token_created and project.token_revoked events are returned to maintainers and above only.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
project | path | string | yes | - |
Responses
| Status | Description | Body |
|---|---|---|
200 | Usage | application/json: ProjectUsage |
400 | Invalid request, including a NUL byte in the URL or the body | application/json: Error |
403 | Forbidden | application/json: Error |
404 | Project not found or the caller is not a member | - |