API Reference
Complete documentation of all HTTP endpoints
The Abacá REST API (abaca-api) is the single HTTP entry point for all Trilio Share Protection operations. Every request must carry a Keystone token scoped to your project. The API is versioned under /v1 and organized into tenant-facing resource groups — targets, policies, backups, restores, jobs, and usage — and operator-only admin resource groups under /v1/admin.
All paginated list endpoints accept the following common query parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
limit | integer (1–1000) | No | Maximum number of items to return in one page. |
marker | string | No | Opaque cursor returned as next_marker in the previous response; pass it to fetch the next page. |
Endpoint-specific parameters are documented under each resource group below.
All successful responses return JSON. Collection endpoints wrap items in a named array alongside a pagination object:
{
"targets": [ ... ],
"pagination": {
"limit": 20,
"count": 3,
"next_marker": null
}
}
Single-resource endpoints return the object directly. Asynchronous create operations (backups, restores, target registration) return HTTP 202 Accepted with both the newly created resource and the associated job:
{
"backup": { ... },
"job": { ... }
}
Synchronous creates (policies) return HTTP 201 Created with the resource only. Deletes return HTTP 204 No Content with an empty body.
Every error response follows the same envelope:
{
"code": "abaca.not_found",
"title": "Not Found",
"detail": "target abc123 not found",
"category": "tenant_action_required"
}
| Field | Type | Description |
|---|---|---|
code | string | Machine-readable error identifier, e.g. abaca.not_found. |
title | string | Short human-readable label. |
detail | string | Full explanation, including the offending resource id where applicable. |
category | tenant_action_required | operator_action_required | Who must act to resolve the error. tenant_action_required means you must fix a configuration (bad bucket credentials, missing field, etc.). operator_action_required means the infrastructure or service needs attention. |
Common HTTP status codes and their meanings across all endpoints:
| Status | When it occurs |
|---|---|
| 400 Bad Request | Missing required field, invalid field value, or attempt to modify an immutable field. |
| 401 Unauthorized | No Keystone token supplied or the token is expired/invalid. |
| 403 Forbidden | Token is valid but lacks the required role (e.g., non-admin accessing /v1/admin/*). |
| 404 Not Found | The requested resource does not exist in your project. |
| 409 Conflict | The operation conflicts with current state — for example, a share already has a policy, a job is not in the required state to cancel or retry, or a policy has in-flight backups blocking deletion. |
| 422 Unprocessable Entity | Preflight conformance checks failed during target registration. |
| 503 Service Unavailable | A backend dependency (e.g., Barbican, Manila) is unreachable. |
Authentication
All requests (except GET /v1/service_info) require a Keystone token in the X-Auth-Token header. Obtain one with your OpenStack credentials:
export OS_TOKEN=$(openstack token issue -f value -c id)
export ABACA_ENDPOINT=https://abaca.example.com/v1
Or use python-abacaclient to issue commands directly:
openstack share protection target list
Targets
Register a backup target
This creates the target record and dispatches the enrollment job, which runs preflight checks and initializes the Kopia repository in your S3 bucket.
curl -s -X POST "$ABACA_ENDPOINT/targets" \
-H "X-Auth-Token: $OS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "my-s3-target",
"endpoint": "https://s3.us-east-1.amazonaws.com",
"bucket": "my-backup-bucket",
"trust_id": "<keystone-trust-id>",
"barbican_secret_map": {
"access_key": "<barbican-secret-href-for-access-key>",
"secret_key": "<barbican-secret-href-for-secret-key>"
},
"addressing_mode": "path"
}'
{
"target": {
"id": "d1e2f3a4-...",
"name": "my-s3-target",
"endpoint": "https://s3.us-east-1.amazonaws.com",
"bucket": "my-backup-bucket",
"status": "pending",
"trust_id": "<keystone-trust-id>",
"barbican_secret_map": {
"access_key": "<barbican-secret-href>",
"secret_key": "<barbican-secret-href>"
},
"ca_cert_ref": null,
"repository_password_ref": null,
"addressing_mode": "path",
"preflight_at": null,
"capabilities": null
},
"job": {
"id": "a1b2c3d4-...",
"job_type": "target_enroll",
"state": "queued",
"progress": 0
}
}
List backup targets
curl -s "$ABACA_ENDPOINT/targets?limit=20" \
-H "X-Auth-Token: $OS_TOKEN"
Show a single target
curl -s "$ABACA_ENDPOINT/targets/d1e2f3a4-..." \
-H "X-Auth-Token: $OS_TOKEN"
Check preflight status
curl -s "$ABACA_ENDPOINT/targets/d1e2f3a4-.../preflight" \
-H "X-Auth-Token: $OS_TOKEN"
{
"target_id": "d1e2f3a4-...",
"status": "available",
"detail": null
}
Update a target (PATCH)
Only name, endpoint, bucket, trust_id, ca_cert_ref, and barbican_secret_refs are editable after creation.
curl -s -X PATCH "$ABACA_ENDPOINT/targets/d1e2f3a4-..." \
-H "X-Auth-Token: $OS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "renamed-target"}'
Delete a target
You must remove all policies and backups referencing this target before deleting it.
curl -s -X DELETE "$ABACA_ENDPOINT/targets/d1e2f3a4-..." \
-H "X-Auth-Token: $OS_TOKEN"
Returns 204 No Content on success.
Policies
Create a protection policy
Binds a Manila share to a backup target with a cron schedule and retention rules.
curl -s -X POST "$ABACA_ENDPOINT/policies" \
-H "X-Auth-Token: $OS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "daily-policy",
"share_id": "<manila-share-id>",
"target_id": "d1e2f3a4-...",
"schedule": "0 2 * * *",
"retention": {
"keep_daily": 7,
"keep_weekly": 4,
"keep_monthly": 12
},
"enabled": true
}'
{
"id": "p1q2r3s4-...",
"name": "daily-policy",
"share_id": "<manila-share-id>",
"target_id": "d1e2f3a4-...",
"schedule": "0 2 * * *",
"retention": {
"keep_daily": 7,
"keep_weekly": 4,
"keep_monthly": 12
},
"enabled": true
}
Update a policy (PATCH)
Editable fields: name, schedule, retention, enabled, include_patterns, exclude_patterns. Identity fields (share_id, target_id, id, project_id) are immutable.
curl -s -X PATCH "$ABACA_ENDPOINT/policies/p1q2r3s4-..." \
-H "X-Auth-Token: $OS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"enabled": false}'
Delete a policy
curl -s -X DELETE "$ABACA_ENDPOINT/policies/p1q2r3s4-..." \
-H "X-Auth-Token: $OS_TOKEN"
Returns 204 No Content. Returns 409 if any backup triggered by this policy is still in the creating state.
Backups
Create an on-demand backup
curl -s -X POST "$ABACA_ENDPOINT/backups" \
-H "X-Auth-Token: $OS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"share_id": "<manila-share-id>",
"target_id": "d1e2f3a4-..."
}'
{
"backup": {
"id": "b1c2d3e4-...",
"share_id": "<manila-share-id>",
"target_id": "d1e2f3a4-...",
"status": "creating",
"kopia_snapshot_id": null,
"crash_consistent": false
},
"job": {
"id": "j1k2l3m4-...",
"job_type": "backup",
"state": "queued",
"progress": 0
}
}
List backups with filters
Filter by share, target, policy, or status. By default, expired backups are hidden.
# All backups for a specific share
curl -s "$ABACA_ENDPOINT/backups?share_id=<manila-share-id>" \
-H "X-Auth-Token: $OS_TOKEN"
# Only available backups for a target
curl -s "$ABACA_ENDPOINT/backups?target_id=d1e2f3a4-...&status=available" \
-H "X-Auth-Token: $OS_TOKEN"
# Include expired tombstones in the audit trail
curl -s "$ABACA_ENDPOINT/backups?include_expired=true" \
-H "X-Auth-Token: $OS_TOKEN"
Delete a backup
curl -s -X DELETE "$ABACA_ENDPOINT/backups/b1c2d3e4-..." \
-H "X-Auth-Token: $OS_TOKEN"
Returns 204 No Content.
Restores
Restore to a new share (default)
curl -s -X POST "$ABACA_ENDPOINT/restores" \
-H "X-Auth-Token: $OS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"backup_id": "b1c2d3e4-..."
}'
Restore a sub-path to a new share
curl -s -X POST "$ABACA_ENDPOINT/restores" \
-H "X-Auth-Token: $OS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"backup_id": "b1c2d3e4-...",
"sub_path": "data/reports/2024"
}'
In-place restore (destructive — requires force)
curl -s -X POST "$ABACA_ENDPOINT/restores" \
-H "X-Auth-Token: $OS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"backup_id": "b1c2d3e4-...",
"mode": "in_place",
"force": true
}'
{
"restore": {
"id": "r1s2t3u4-...",
"backup_id": "b1c2d3e4-...",
"mode": "in_place",
"force": true,
"sub_path": null,
"status": "pending"
},
"job": {
"id": "j5k6l7m8-...",
"job_type": "restore",
"state": "queued",
"progress": 0
}
}
Jobs
Poll a job until it reaches a terminal state
curl -s "$ABACA_ENDPOINT/jobs/j1k2l3m4-..." \
-H "X-Auth-Token: $OS_TOKEN"
{
"id": "j1k2l3m4-...",
"job_type": "backup",
"state": "transferring",
"progress": 62
}
Terminal states are available (success) and error (failure). On error, check the error_category field to determine whether you or the operator needs to act.
Filter jobs by resource
# Jobs for a specific backup
curl -s "$ABACA_ENDPOINT/jobs?resource_id=b1c2d3e4-..." \
-H "X-Auth-Token: $OS_TOKEN"
# Jobs for a specific target
curl -s "$ABACA_ENDPOINT/jobs?target_id=d1e2f3a4-..." \
-H "X-Auth-Token: $OS_TOKEN"
Usage
Get your tenant usage summary
curl -s "$ABACA_ENDPOINT/usage" \
-H "X-Auth-Token: $OS_TOKEN"
{
"project_id": "<your-project-id>",
"protected_shares": 4,
"backup_count": 28,
"protected_bytes": 107374182400,
"stored_bytes": 21474836480
}
Service Info (unauthenticated)
Returns the identity of the Abacá service account. Use this during enrollment to look up the trustee user ID needed to create a Keystone trust, without requiring user-list privileges.
curl -s "$ABACA_ENDPOINT/service_info"
{
"service_user": {
"id": "<service-user-uuid>",
"name": "abaca"
},
"worker_project": {
"id": "<worker-project-uuid>",
"name": "abaca-workers"
}
}
Admin: Fleet and Operations
All /v1/admin/* endpoints require the OpenStack admin role.
List all workers across all tenants
curl -s "$ABACA_ENDPOINT/admin/workers" \
-H "X-Auth-Token: $OS_TOKEN"
Drain a worker (stop accepting new jobs)
curl -s -X POST "$ABACA_ENDPOINT/admin/workers/<worker_id>/drain" \
-H "X-Auth-Token: $OS_TOKEN"
Retire a worker (permanently remove from fleet)
curl -s -X POST "$ABACA_ENDPOINT/admin/workers/<worker_id>/retire" \
-H "X-Auth-Token: $OS_TOKEN"
Retry a failed job
curl -s -X POST "$ABACA_ENDPOINT/admin/jobs/<job_id>/retry" \
-H "X-Auth-Token: $OS_TOKEN"
Only jobs in error state can be retried. Returns 409 otherwise.
Cancel a running job
curl -s -X POST "$ABACA_ENDPOINT/admin/jobs/<job_id>/cancel" \
-H "X-Auth-Token: $OS_TOKEN"
Returns 409 if the job is already in a terminal state (available or error).
Get protection coverage report
curl -s "$ABACA_ENDPOINT/admin/coverage" \
-H "X-Auth-Token: $OS_TOKEN"
{
"coverage": [
{
"share_id": "<manila-share-id>",
"project_id": "<project-id>",
"policy_id": "p1q2r3s4-...",
"target_id": "d1e2f3a4-...",
"protected": true,
"backup_count": 7
}
],
"pagination": { "count": 1 }
}
Pause and resume the scheduler
# Pause all scheduled backup triggers
curl -s -X POST "$ABACA_ENDPOINT/admin/scheduling/pause" \
-H "X-Auth-Token: $OS_TOKEN"
# Resume scheduling
curl -s -X POST "$ABACA_ENDPOINT/admin/scheduling/resume" \
-H "X-Auth-Token: $OS_TOKEN"
# Check current scheduling state
curl -s "$ABACA_ENDPOINT/admin/scheduling" \
-H "X-Auth-Token: $OS_TOKEN"
Trigger reconciliation manually
curl -s -X POST "$ABACA_ENDPOINT/admin/reconciliation/trigger" \
-H "X-Auth-Token: $OS_TOKEN"
{ "status": "triggered" }
Check reconciliation status
curl -s "$ABACA_ENDPOINT/admin/reconciliation" \
-H "X-Auth-Token: $OS_TOKEN"
{
"loops": ["manila_polling", "orphan_sweep", "rebuild_from_repository"],
"status": "idle"
}
API versioning
All endpoints are under the /v1 prefix, which the API server mounts at the server root. The full base URL is therefore https://<your-abaca-host>/v1. The current API version is encoded in openapi.yaml and is generated from the source; check GET /v1/service_info for runtime identity information.
Authentication and Keystone tokens
Every request (except GET /v1/service_info) must include a valid Keystone token in the X-Auth-Token header, scoped to your project. The abaca-api service validates the token against Keystone on every request. Abacá never stores your credentials — it holds only Barbican secret hrefs. Your S3 access keys and the Kopia repository password are fetched from Barbican at job execution time using a delegated Keystone trust, and are never written to disk.
Enrollment prerequisite for backups and restores
A backup or restore job is only dispatched to the conductor if its target is fully enrolled — meaning trust_id, barbican_secret_map.access_key, barbican_secret_map.secret_key, and repository_password_ref are all present. If you register a target with bare fields (no trust or secret map), the target stays pending and any backup or restore job created against it will remain in the queued state until enrollment completes. You can PATCH the target to add the missing fields and then re-trigger enrollment.
Job state machine
Every asynchronous operation — backup, restore, or target enrollment — is tracked as a job that moves through a fixed sequence of states:
queued → provisioning_network → provisioning_source → connecting_repository → transferring → finalizing → releasing → available (success) or error (failure)
Poll GET /v1/jobs/<job_id> to follow progress. The progress field is an integer (0–100). On error, inspect error_category to determine who must act: tenant_action_required (you need to fix a configuration) or operator_action_required (infrastructure needs attention).
Pagination
All list endpoints use cursor-based pagination. Pass limit to control page size (default varies, maximum 1000). When the response includes a non-null next_marker, pass it as the marker query parameter to fetch the next page. A null next_marker means you have reached the last page.
Backup expiry and the include_expired flag
Expired backups (status expired) are tombstone records — they are no longer restorable because their Kopia snapshots have been pruned by the retention policy. They are hidden from GET /v1/backups by default to avoid drowning the list with historical rows. Pass ?include_expired=true to see the full audit trail, or pass ?status=expired to scope to expired records exclusively.
Policy immutability constraints
A policy's share_id and target_id are immutable after creation. Changing them would orphan every backup the policy has already produced (those backups reference the original share and target in the Kopia repository). Attempting to PATCH these fields returns HTTP 400 with error code abaca.field_immutable. To move a share to a different target, delete the old policy (after its in-flight backups complete) and create a new one.
In-place restore requires force: true
An in-place restore (mode: in_place) overwrites the current contents of the original share. Because this is a destructive and irreversible operation, it requires an explicit "force": true in the request body. Omitting force or setting it to false returns HTTP 400 immediately.
Deleting a target requires clearing dependents first
You cannot delete a backup target that still has policies or backups referencing it. Delete or detach all associated policies and backups first. Job history and usage meter records are handled automatically: job rows are hard-deleted, and usage meter rows have their target_id nulled out (preserving billing history).
Deleting a policy with in-flight backups
If a scheduled backup is still in the creating state when you attempt to delete its policy, the API returns HTTP 409 with error code abaca.policy_has_inflight_backup. Wait for the backup to reach a terminal state (available or error), or wait for the reconciliation loop's stuck-job sweep to walk it to error, then retry the delete. Backups that were already completed before the delete are detached from the policy (their policy_id is set to null) but are not deleted — they remain as restorable recovery points.
Supported S3-compatible backends
Abacá works with AWS S3, MinIO, Ceph RGW, ODF, and Wasabi. Your bucket must have S3 object lock enabled at creation time — object lock cannot be added to an existing bucket. Preflight checks validate bucket reachability, read/write access, addressing style, object lock configuration, and the absence of expiration lifecycle rules that could silently delete backup objects.
FIPS mode
FIPS 140 is a supported, validated production configuration. When FIPS mode is active, Abacá configures Kopia to use only FIPS-approved encryption and hash algorithms, and worker VMs run in RHEL FIPS mode. No API changes are required to use FIPS mode — it is an operator-level configuration of the worker image and control plane.
OpenAPI specification
The authoritative OpenAPI 3 contract for all request and response shapes, required fields, and status codes is published at docs/api-ref/openapi.yaml. It is generated programmatically from the service's route definitions via python -m abaca.api.openapi and must not be edited by hand. When in doubt about a specific field type or constraint, consult that file directly.