Storage policies and retention
Quotas, usage, retention policies, their preview and run, cleanup and deletion of artifacts.
Operations of this group with their access rule, retry rule, parameters and answers. Every request carries a key: Authorization: Bearer <key> (see Authentication).
Operations
Check whether an artifact can be deleted
GET HEAD /api/v1/repositories/{repository}/artifacts/{id}/deletion
Access: Repository permission: artifact.delete · Retry: Safe to repeat (read)
Returns the artifact's name, size, publication time, current annotationRevision and the blockers that would keep it from deletion: reference (an external reference, or use by a container image, Git LFS or npm), asset_history (a current or earlier file path revision), attachment_history or promotion_stage. Nothing changes; pass the revision to deleteArtifact as expectedAnnotationRevision.
Parameters
| Name | In | Type | Required | Rules |
|---|---|---|---|---|
repository | path | string | yes | matches ^[a-z0-9][a-z0-9_-]{0,63}$ |
id | path | string (uuid) | yes | — |
Response 200
| Field | Type | Required | Rules |
|---|---|---|---|
id | string (uuid) | yes | — |
name | string | yes | 1–240 characters |
size | string | yes | a whole number in decimal digits, sent as a string |
publishedAt | string (date-time) | yes | — |
annotationRevision | integer | yes | 0–2147483647 |
blockers | array of string | yes | up to 4 items; no repeated items; each: one of reference, asset_history, attachment_history, protected_label, promotion_stage |
Responses: 200, 400, 401, 403, 404, 409, 422, 503, 507
Example
curl -X GET "$ARKVORY_URL/api/v1/repositories/$REPOSITORY/artifacts/$ID/deletion" \
-H "Authorization: Bearer $ARKVORY_TOKEN"Preview retention candidates
POST /api/v1/repositories/{repository}/retention/preview
Access: Repository permission: artifact.delete · Retry: Safe to repeat (read)
Lists the published artifacts released before criteria.publishedBefore (a past UTC time with milliseconds), ordered by ID, each with its annotation revision and blockers, protected_label meaning one of criteria.protectedLabels (an explicit list of up to 32). Pages hold limit items (1–100, default 50); continue with after set to next. Nothing is reserved: choose the items to delete and pass them with their revisions to applyRetention, which checks them again.
Parameters
| Name | In | Type | Required | Rules |
|---|---|---|---|---|
repository | path | string | yes | matches ^[a-z0-9][a-z0-9_-]{0,63}$ |
Request body (application/json)
| Field | Type | Required | Rules |
|---|---|---|---|
criteria | object | yes | — |
criteria.publishedBefore | string (date-time) | yes | matches ^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d\.\d{3}Z$ |
criteria.protectedLabels | array of string | yes | up to 32 items; no repeated items; each: 1–64 characters |
limit | integer | no | 1–100 |
after | string (uuid) | no | — |
Response 200
| Field | Type | Required | Rules |
|---|---|---|---|
items | array of object | yes | up to 100 items |
items[].id | string (uuid) | yes | — |
items[].name | string | yes | 1–240 characters |
items[].size | string | yes | a whole number in decimal digits, sent as a string |
items[].publishedAt | string (date-time) | yes | — |
items[].annotationRevision | integer | yes | 0–2147483647 |
items[].blockers | array of string | yes | up to 4 items; no repeated items; each: one of reference, asset_history, attachment_history, protected_label, promotion_stage |
next | string (uuid) | yes | may be null |
Responses: 200, 400, 401, 403, 404, 405, 409, 413, 415, 422, 503, 507
Example
curl -X POST "$ARKVORY_URL/api/v1/repositories/$REPOSITORY/retention/preview" \
-H "Authorization: Bearer $ARKVORY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"criteria":{"publishedBefore":"2026-01-01T00:00:00.000Z","protectedLabels":[]}}'Delete the selected retention candidates
POST /api/v1/repositories/{repository}/retention/apply
Access: Repository permission: artifact.delete · Retry: Safe to repeat: the same request has the same effect
Rechecks 1–100 artifacts chosen from previewRetention (items with id and expectedAnnotationRevision) against the same criteria and logically deletes the eligible ones in one transaction. Each item gets an outcome: deleted, already_deleted, changed (the annotations changed), not_eligible (published too late), protected with its blockers, or not_found. The bytes stay reserved until the repository's online cleanup reclaims them.
Parameters
| Name | In | Type | Required | Rules |
|---|---|---|---|---|
repository | path | string | yes | matches ^[a-z0-9][a-z0-9_-]{0,63}$ |
Request body (application/json)
| Field | Type | Required | Rules |
|---|---|---|---|
criteria | object | yes | — |
criteria.publishedBefore | string (date-time) | yes | matches ^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d\.\d{3}Z$ |
criteria.protectedLabels | array of string | yes | up to 32 items; no repeated items; each: 1–64 characters |
items | array of object | yes | 1–100 items |
items[].id | string (uuid) | yes | — |
items[].expectedAnnotationRevision | integer | yes | 0–2147483647 |
Response 200
| Field | Type | Required | Rules |
|---|---|---|---|
items | array of object | yes | 1–100 items |
items[].id | string (uuid) | yes | — |
items[].outcome | string | yes | one of deleted, already_deleted, protected, changed, not_eligible, not_found |
items[].blockers | array of string | yes | up to 4 items; no repeated items; each: one of reference, asset_history, attachment_history, protected_label, promotion_stage |
Responses: 200, 400, 401, 403, 404, 405, 409, 413, 415, 422, 503, 507
Example
curl -X POST "$ARKVORY_URL/api/v1/repositories/$REPOSITORY/retention/apply" \
-H "Authorization: Bearer $ARKVORY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"criteria":{"publishedBefore":"2026-01-01T00:00:00.000Z","protectedLabels":[]},"items":[{"id":"00000000-0000-4000-8000-000000000000","expectedAnnotationRevision":0}]}'Get the storage policy
GET HEAD /api/v1/repositories/{repository}/storage/policy
Access: Repository permission: storage.read · Retry: Safe to repeat (read)
Returns the repository's automatic cleanup and quota settings with their revision, the next and last scheduled run, how many builds the last run deleted and its error. By default the policy is disabled and there is no repository quota (the server-wide capacity still applies).
Parameters
| Name | In | Type | Required | Rules |
|---|---|---|---|---|
repository | path | string | yes | matches ^[a-z0-9][a-z0-9_-]{0,63}$ |
Response 200
| Field | Type | Required | Rules |
|---|---|---|---|
revision | integer | yes | 0–2147483647 |
policy | object | yes | — |
policy.enabled | boolean | yes | — |
policy.grouping | string | yes | one of package-channel, package, repository |
policy.keepLast | integer | yes | 1–100000 |
policy.channels | array of object | yes | up to 32 items |
policy.channels[].label | string | yes | 1–64 characters |
policy.channels[].keepLast | integer | yes | 1–100000 |
policy.protectedLabels | array of string | yes | up to 32 items; no repeated items; each: 1–64 characters |
policy.minAgeHours | integer | yes | 0–87600 |
policy.intervalMinutes | integer | yes | 1–10080 |
policy.quotaBytes | string | yes | a whole number in decimal digits, sent as a string; may be null |
policy.warningPercent | integer | yes | 1–98 |
policy.criticalPercent | integer | yes | 2–99 |
nextRunAt | string (date-time) | yes | may be null |
lastRunAt | string (date-time) | yes | may be null |
lastDeleted | integer | yes | 0–100 |
lastError | string | yes | up to 64 characters; may be null |
Responses: 200, 400, 401, 403, 404, 409, 422, 503, 507
Example
curl -X GET "$ARKVORY_URL/api/v1/repositories/$REPOSITORY/storage/policy" \
-H "Authorization: Bearer $ARKVORY_TOKEN"Replace the storage policy
PUT /api/v1/repositories/{repository}/storage/policy
Access: Repository permission: storage.manage · Retry: Repeat only with the expected revision (compare-and-swap)
Replaces the whole policy: keep the last keepLast registered UPack builds per package, per channel label (channels) or per repository (grouping), never delete protectedLabels or builds younger than minAgeHours, run every intervalMinutes, and limit the repository with quotaBytes (a decimal string, null for none) and its warning thresholds. expectedRevision must be the current revision, otherwise 409 revision_mismatch. Enabling also needs artifact.delete and ties the schedule to the calling managed key: once that key is revoked, expires or loses these permissions, scheduled deletion stops until the policy is saved with another key. Ordinary files count against the quota but are never deleted by it.
Parameters
| Name | In | Type | Required | Rules |
|---|---|---|---|---|
repository | path | string | yes | matches ^[a-z0-9][a-z0-9_-]{0,63}$ |
Request body (application/json)
| Field | Type | Required | Rules |
|---|---|---|---|
expectedRevision | integer | yes | 0–2147483647 |
policy | object | yes | — |
policy.enabled | boolean | yes | — |
policy.grouping | string | yes | one of package-channel, package, repository |
policy.keepLast | integer | yes | 1–100000 |
policy.channels | array of object | yes | up to 32 items |
policy.channels[].label | string | yes | 1–64 characters |
policy.channels[].keepLast | integer | yes | 1–100000 |
policy.protectedLabels | array of string | yes | up to 32 items; no repeated items; each: 1–64 characters |
policy.minAgeHours | integer | yes | 0–87600 |
policy.intervalMinutes | integer | yes | 1–10080 |
policy.quotaBytes | string | yes | a whole number in decimal digits, sent as a string; may be null |
policy.warningPercent | integer | yes | 1–98 |
policy.criticalPercent | integer | yes | 2–99 |
Response 200
| Field | Type | Required | Rules |
|---|---|---|---|
revision | integer | yes | 0–2147483647 |
policy | object | yes | — |
policy.enabled | boolean | yes | — |
policy.grouping | string | yes | one of package-channel, package, repository |
policy.keepLast | integer | yes | 1–100000 |
policy.channels | array of object | yes | up to 32 items |
policy.channels[].label | string | yes | 1–64 characters |
policy.channels[].keepLast | integer | yes | 1–100000 |
policy.protectedLabels | array of string | yes | up to 32 items; no repeated items; each: 1–64 characters |
policy.minAgeHours | integer | yes | 0–87600 |
policy.intervalMinutes | integer | yes | 1–10080 |
policy.quotaBytes | string | yes | a whole number in decimal digits, sent as a string; may be null |
policy.warningPercent | integer | yes | 1–98 |
policy.criticalPercent | integer | yes | 2–99 |
nextRunAt | string (date-time) | yes | may be null |
lastRunAt | string (date-time) | yes | may be null |
lastDeleted | integer | yes | 0–100 |
lastError | string | yes | up to 64 characters; may be null |
Responses: 200, 400, 401, 403, 404, 405, 409, 413, 415, 422, 503, 507
Example
curl -X PUT "$ARKVORY_URL/api/v1/repositories/$REPOSITORY/storage/policy" \
-H "Authorization: Bearer $ARKVORY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"expectedRevision":0,"policy":{"enabled":false,"grouping":"package-channel","keepLast":1,"channels":[],"protectedLabels":[],"minAgeHours":0,"intervalMinutes":1,"quotaBytes":"1024","warningPercent":1,"criticalPercent":2}}'Get the storage usage of a repository
GET HEAD /api/v1/repositories/{repository}/storage/usage
Access: Repository permission: storage.read · Retry: Safe to repeat (read)
Returns the bytes reserved by the repository as decimal strings: published, pending uploads and retired (deleted or cancelled, not yet reclaimed), their sum reservedBytes, the quota and a state (unlimited, normal, warning, critical, exceeded). This is the logical reservation counted against the quota, not the space used on disk.
Parameters
| Name | In | Type | Required | Rules |
|---|---|---|---|---|
repository | path | string | yes | matches ^[a-z0-9][a-z0-9_-]{0,63}$ |
Response 200
| Field | Type | Required | Rules |
|---|---|---|---|
publishedBytes | string | yes | a whole number in decimal digits, sent as a string |
pendingBytes | string | yes | a whole number in decimal digits, sent as a string |
retiredBytes | string | yes | a whole number in decimal digits, sent as a string |
reservedBytes | string | yes | a whole number in decimal digits, sent as a string |
quotaBytes | string | yes | a whole number in decimal digits, sent as a string; may be null |
state | string | yes | one of unlimited, normal, warning, critical, exceeded |
Responses: 200, 400, 401, 403, 404, 409, 422, 503, 507
Example
curl -X GET "$ARKVORY_URL/api/v1/repositories/$REPOSITORY/storage/usage" \
-H "Authorization: Bearer $ARKVORY_TOKEN"Preview what the storage policy would delete
GET HEAD /api/v1/repositories/{repository}/storage/preview
Access: Repository permission: artifact.delete · Retry: Safe to repeat (read)
Returns up to 100 registered builds the saved policy would delete now (even while it is disabled), with the policy revision and hasMore; builds kept by references, file paths, attachments, protected labels or age are left out. Nothing is reserved: a run ranks the builds again.
Parameters
| Name | In | Type | Required | Rules |
|---|---|---|---|---|
repository | path | string | yes | matches ^[a-z0-9][a-z0-9_-]{0,63}$ |
Response 200
| Field | Type | Required | Rules |
|---|---|---|---|
revision | integer | yes | 0–2147483647 |
items | array of object | yes | up to 100 items |
items[].id | string (uuid) | yes | — |
items[].name | string | yes | up to 240 characters |
items[].size | string | yes | a whole number in decimal digits, sent as a string |
items[].publishedAt | string (date-time) | yes | — |
items[].annotationRevision | integer | yes | 0–2147483647 |
items[].blockers | array of string | yes | up to 0 items |
hasMore | boolean | yes | — |
Responses: 200, 400, 401, 403, 404, 409, 422, 503, 507
Example
curl -X GET "$ARKVORY_URL/api/v1/repositories/$REPOSITORY/storage/preview" \
-H "Authorization: Bearer $ARKVORY_TOKEN"Run the storage policy now
POST /api/v1/repositories/{repository}/storage/run
Access: Repository permission: storage.manage, artifact.delete · Retry: Do not repeat automatically
Runs one batch of the enabled policy at once instead of waiting for the schedule: it ranks the builds again, checks permissions and dependencies, and logically deletes up to 100, returning an outcome for each. expectedRevision must be the current policy revision and the policy must be enabled, otherwise 409. The bytes are reclaimed later by the repository's online cleanup, which has its own policy (setCleanup).
Parameters
| Name | In | Type | Required | Rules |
|---|---|---|---|---|
repository | path | string | yes | matches ^[a-z0-9][a-z0-9_-]{0,63}$ |
Request body (application/json)
| Field | Type | Required | Rules |
|---|---|---|---|
expectedRevision | integer | yes | 0–2147483647 |
Response 200
| Field | Type | Required | Rules |
|---|---|---|---|
items | array of object | yes | up to 100 items |
items[].id | string (uuid) | yes | — |
items[].outcome | string | yes | one of deleted, already_deleted, protected, changed, not_eligible, not_found |
items[].blockers | array of string | yes | up to 4 items; each: one of reference, asset_history, attachment_history, protected_label, promotion_stage |
Responses: 200, 400, 401, 403, 404, 405, 409, 413, 415, 422, 503, 507
Example
curl -X POST "$ARKVORY_URL/api/v1/repositories/$REPOSITORY/storage/run" \
-H "Authorization: Bearer $ARKVORY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"expectedRevision":0}'List the storage events of a repository
GET HEAD /api/v1/repositories/{repository}/storage/events
Access: Repository permission: diagnostics.read · Retry: Safe to repeat (read)
Returns up to 100 diagnostic events of storage policies, quotas, retention and cleanup after the sequence after (default 0), oldest first, each with level, code and a few details; level (info, warning, error) filters them, continue with after set to next. Only the newest 1000 events per repository and 20 000 overall are kept, so export them for longer retention.
Parameters
| Name | In | Type | Required | Rules |
|---|---|---|---|---|
repository | path | string | yes | matches ^[a-z0-9][a-z0-9_-]{0,63}$ |
after | query | string | no | a whole number in decimal digits, sent as a string |
level | query | string | no | one of info, warning, error |
Response 200
| Field | Type | Required | Rules |
|---|---|---|---|
items | array of object | yes | up to 100 items |
items[].sequence | string | yes | a whole number in decimal digits, sent as a string |
items[].occurredAt | string (date-time) | yes | — |
items[].level | string | yes | one of info, warning, error |
items[].code | string | yes | up to 96 characters |
items[].details | map of string | integer | yes | up to 16 entries |
next | string | yes | a whole number in decimal digits, sent as a string; may be null |
Responses: 200, 400, 401, 403, 404, 409, 422, 503, 507
Example
curl -X GET "$ARKVORY_URL/api/v1/repositories/$REPOSITORY/storage/events" \
-H "Authorization: Bearer $ARKVORY_TOKEN"Get the online cleanup settings
GET HEAD /api/v1/repositories/{repository}/storage/cleanup
Access: Repository permission: storage.read · Retry: Safe to repeat (read)
Returns the repository's online cleanup policy with its revision (enabled, graceHours, batchSize, intervalSeconds, delayMilliseconds), the last and next run, and how many objects the last batch reclaimed, deferred or failed with the bytes freed. Cleanup is what physically removes cancelled uploads and deleted artifacts; it is off by default.
Parameters
| Name | In | Type | Required | Rules |
|---|---|---|---|---|
repository | path | string | yes | matches ^[a-z0-9][a-z0-9_-]{0,63}$ |
Response 200
| Field | Type | Required | Rules |
|---|---|---|---|
revision | integer | yes | 0–2147483647 |
policy | object | yes | — |
policy.enabled | boolean | yes | — |
policy.graceHours | integer | yes | 0–8760 |
policy.batchSize | integer | yes | 1–100 |
policy.intervalSeconds | integer | yes | 5–86400 |
policy.delayMilliseconds | integer | yes | 0–1000 |
lastRunAt | string (date-time) | yes | may be null |
nextRunAt | string (date-time) | yes | may be null |
lastCollected | integer | yes | 0–100 |
lastDeferred | integer | yes | 0–100 |
lastFailed | integer | yes | 0–100 |
lastReclaimedBytes | string | yes | a whole number in decimal digits, sent as a string |
lastError | string | yes | may be null |
Responses: 200, 400, 401, 403, 404, 409, 422, 503, 507
Example
curl -X GET "$ARKVORY_URL/api/v1/repositories/$REPOSITORY/storage/cleanup" \
-H "Authorization: Bearer $ARKVORY_TOKEN"Configure online cleanup
PUT /api/v1/repositories/{repository}/storage/cleanup
Access: Repository permission: storage.manage · Retry: Repeat only with the expected revision (compare-and-swap)
Replaces the cleanup policy while the server runs: enabled (also to pause), graceHours (0–8760, how long deleted content stays before removal), batchSize (1–100 objects), intervalSeconds (5–86400) and delayMilliseconds (0–1000 between objects). expectedRevision must be the current revision (0 before the first change), otherwise 409 revision_mismatch. A change takes effect between objects, never halfway through one.
Parameters
| Name | In | Type | Required | Rules |
|---|---|---|---|---|
repository | path | string | yes | matches ^[a-z0-9][a-z0-9_-]{0,63}$ |
Request body (application/json)
| Field | Type | Required | Rules |
|---|---|---|---|
expectedRevision | integer | yes | 0–2147483647 |
policy | object | yes | — |
policy.enabled | boolean | yes | — |
policy.graceHours | integer | yes | 0–8760 |
policy.batchSize | integer | yes | 1–100 |
policy.intervalSeconds | integer | yes | 5–86400 |
policy.delayMilliseconds | integer | yes | 0–1000 |
Response 200
| Field | Type | Required | Rules |
|---|---|---|---|
revision | integer | yes | 0–2147483647 |
policy | object | yes | — |
policy.enabled | boolean | yes | — |
policy.graceHours | integer | yes | 0–8760 |
policy.batchSize | integer | yes | 1–100 |
policy.intervalSeconds | integer | yes | 5–86400 |
policy.delayMilliseconds | integer | yes | 0–1000 |
lastRunAt | string (date-time) | yes | may be null |
nextRunAt | string (date-time) | yes | may be null |
lastCollected | integer | yes | 0–100 |
lastDeferred | integer | yes | 0–100 |
lastFailed | integer | yes | 0–100 |
lastReclaimedBytes | string | yes | a whole number in decimal digits, sent as a string |
lastError | string | yes | may be null |
Responses: 200, 400, 401, 403, 404, 405, 409, 413, 415, 422, 503, 507
Example
curl -X PUT "$ARKVORY_URL/api/v1/repositories/$REPOSITORY/storage/cleanup" \
-H "Authorization: Bearer $ARKVORY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"expectedRevision":0,"policy":{"enabled":false,"graceHours":0,"batchSize":1,"intervalSeconds":5,"delayMilliseconds":0}}'Request a cleanup batch now
POST /api/v1/repositories/{repository}/storage/cleanup/run
Access: Repository permission: storage.manage · Retry: Do not repeat automatically
Schedules the next batch of the enabled cleanup policy to start at once; the answer is the cleanup state, and the bytes are freed only when the batch has run (see lastRunAt in getCleanup). expectedRevision must be the current revision; a disabled cleanup is a 409 state_conflict. Objects that are being read or written are deferred to a later batch.
Parameters
| Name | In | Type | Required | Rules |
|---|---|---|---|---|
repository | path | string | yes | matches ^[a-z0-9][a-z0-9_-]{0,63}$ |
Request body (application/json)
| Field | Type | Required | Rules |
|---|---|---|---|
expectedRevision | integer | yes | 0–2147483647 |
Response 200
| Field | Type | Required | Rules |
|---|---|---|---|
revision | integer | yes | 0–2147483647 |
policy | object | yes | — |
policy.enabled | boolean | yes | — |
policy.graceHours | integer | yes | 0–8760 |
policy.batchSize | integer | yes | 1–100 |
policy.intervalSeconds | integer | yes | 5–86400 |
policy.delayMilliseconds | integer | yes | 0–1000 |
lastRunAt | string (date-time) | yes | may be null |
nextRunAt | string (date-time) | yes | may be null |
lastCollected | integer | yes | 0–100 |
lastDeferred | integer | yes | 0–100 |
lastFailed | integer | yes | 0–100 |
lastReclaimedBytes | string | yes | a whole number in decimal digits, sent as a string |
lastError | string | yes | may be null |
Responses: 200, 400, 401, 403, 404, 405, 409, 413, 415, 422, 503, 507
Example
curl -X POST "$ARKVORY_URL/api/v1/repositories/$REPOSITORY/storage/cleanup/run" \
-H "Authorization: Bearer $ARKVORY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"expectedRevision":0}'