You can use the Preservation actions API to run preservation actions on packages, follow their progress, and read the results. A preservation action is a task that the archive runs on a package, such as calculating fixity information or validating PDF/A files. It keeps the files usable and verifiable.
When you start an action, the call returns at once, and you follow the run with a status call. You can also schedule actions to run on a regular basis.
Every call needs the headers in Common headers.
How a run works
-
To find the action names, list the enabled actions with
GET /v2/preservation-action?onlyEnabled=true. -
Start the run with
POST /v2/preservation-action/execute. The response holds anexecutionId. -
Poll
GET /v2/preservation-action/bulk/{executionId}untilstatusisCOMPLETEDorFAILED. -
To see the result on each package, list the execution reports with
GET /v2/preservation-action/reports.
List the available actions
Returns the preservation actions, enabled or not, with their order and settings. Only enabled actions can run.
GET /v2/preservation-action
Required role: archive-content-manager
|
Name |
Type |
Required |
Description |
|---|---|---|---|
|
|
boolean |
No |
If |
Response: 200 OK with a PreservationActionList.
{
"items": [
{
"name": "fixityInformationPlugin",
"enabled": true,
"order": 40,
"properties": {
"algorithm": "SHA256"
}
},
{
"name": "pdfValidationPlugin",
"enabled": true,
"order": 30
}
]
}
Run actions on packages
Starts one or more preservation actions on a set of packages. Pick the packages in one of three ways:
-
packageIds: a list of package IDs. -
criteria: a query that finds the packages. For the format, see QueryCriteria. -
allPackages: set it totrueto run on every package in the archive. If you leave out all three, the call fails.
The archive skips the packages that you aren't allowed to manage, and the packages in the trash.
POST /v2/preservation-action/execute
Required role: archive-content-manager
|
Name |
Type |
Required |
Description |
|---|---|---|---|
|
|
array of strings |
Yes, or |
The names of the actions to run, from List the available actions. |
|
|
string |
No |
Deprecated. The name of one action. Ignored if |
|
|
array of strings |
One of three |
The IDs of the packages. |
|
|
One of three |
A query that finds the packages. |
|
|
|
boolean |
One of three |
Set to |
On each package, the actions run in the order of the actionNames list. If an action ends in FAILURE on a package, the next actions don't run on that package.
Caution: Check the action names before you start a run. A name that isn't an enabled action still gives 202, but then none of the actions runs on any package, and no execution reports appear.
Tip: To run an action on a package set, list its packages with the Package sets API, and send their IDs in packageIds.
curl -X POST "https://archive.example.com/v2/preservation-action/execute" \
-H "Authorization: Bearer $TOKEN" \
-H "tenant: example-tenant" \
-H "Content-Type: application/json" \
-d '{
"actionNames": ["fixityInformationPlugin", "pdfValidationPlugin"],
"packageIds": ["HR-2019-0042", "HR-2019-0043"]
}'
Response: 202 Accepted with a BulkPreservationActionResult. The actions are queued, not done. Keep the executionId to follow the run.
{
"executionId": "6f1c2a9e-4b7d-4f0e-9a51-3c2d8e7b1a40",
"status": "PENDING",
"totalPackages": 0,
"processedPackages": 0,
"errorCount": 0
}
-
400withREQUIRED_FIELD: there's no action name, or you didn't pick any packages. -
400withMUTUALLY_EXCLUSIVE_FIELDS: you used more than one ofpackageIds,criteria, andallPackages. -
400: thecriteriaisn't valid. Thereasonanddetailssay which rule:UNKNOWN_QUERY_FIELD,OPERATOR_NOT_ALLOWED,INVALID_QUERY_CRITERIA,REQUIRED_FIELD,INVALID_VALUE,INVALID_DATE, orINVALID_FORMAT.
Follow a run
Returns the progress of a run that you started with Run actions on packages or Run a schedule now. Call it every few seconds until status is COMPLETED or FAILED.
GET /v2/preservation-action/bulk/{executionId}
Required role: archive-content-manager
|
Name |
Type |
Required |
Description |
|---|---|---|---|
|
|
string |
Yes |
The |
Response: 200 OK with a BulkPreservationActionResult.
-
404withEXECUTION_NOT_FOUND: the archive doesn't know thisexecutionId.
List execution reports
Each time an action runs on a package, the archive records the result in an execution report. You can list these reports for all packages, and filter them.
GET /v2/preservation-action/reports
Required role: archive-content-manager
|
Name |
Type |
Required |
Description |
|---|---|---|---|
|
|
array of strings |
No |
Only reports for these actions. Separate the names with commas, or repeat the parameter. |
|
|
array of strings |
No |
Only reports with these results: |
|
|
string |
No |
Only reports for this package. |
|
|
string |
No |
Only reports from this moment on. Use |
|
|
string |
No |
Only reports up to this moment. Same formats as |
|
|
string |
No |
|
|
|
string |
No |
|
|
|
integer |
No |
The page number, starting at 0. Default: |
|
|
integer |
No |
The number of reports per page. Default: |
Response: 200 OK with a PreservationActionReportList.
{
"totalResults": 1,
"page": 0,
"pageSize": 100,
"items": [
{
"actionName": "pdfValidationPlugin",
"packageId": "HR-2019-0042",
"status": "WARNING",
"executionDate": "2026-09-30T14:02:11Z",
"message": "contract.pdf isn't valid PDF/A"
}
]
}
-
400withUNSUPPORTED_VALUE: astatusvalue isn't one of the three results. -
400withINVALID_DATE:fromortoisn't in one of the formats.
Export execution reports
Downloads the execution reports as a CSV file. It takes the same filters as List execution reports, and returns every matching report, without pages.
GET /v2/preservation-action/reports/export
Required role: archive-content-manager
Query parameters: actionName, status, packageId, from, and to, as in List execution reports.
Response: 200 OK with a text/csv file. The first line holds the column names:
pluginName,packageId,status,executionDate,message
The pluginName column holds the action name.
Schedule actions
A schedule runs one or more actions on the packages that match a query, at the times that you set. The archive starts the schedule's runs on its own, and you can also start one at any time.
When a schedule runs
Set the schedule field to a Quartz cron expression, for example:
-
0 0 2 * * ?: every day at 2 AM. -
0 30 1 ? * SUN: every Sunday at 1:30 AM. -
0 0 3 1 * ?: on the first day of every month at 3 AM.
An expression has six or seven fields, from the seconds to an optional year. The archive refuses an expression that isn't valid or that has a value out of range, such as 61 minutes.
A run that a schedule starts on its own isn't limited by what you can manage. It covers every package that matches the query.
List schedules
GET /v2/preservation-action/schedules
Required role: archive-content-manager
Response: 200 OK with a PreservationScheduleList, sorted by name.
Get a schedule
GET /v2/preservation-action/schedules/{scheduleId}
Required role: archive-content-manager
|
Name |
Type |
Required |
Description |
|---|---|---|---|
|
|
string |
Yes |
The ID of the schedule. |
Response: 200 OK with a PreservationSchedule.
-
404: there's no schedule with this ID.
Create a schedule
Sets up a schedule. It starts running at the next time that matches schedule.
POST /v2/preservation-action/schedules
Required role: archive-content-manager
|
Name |
Type |
Required |
Description |
|---|---|---|---|
|
|
string |
Yes |
The name of the schedule. |
|
|
string |
No |
A description. |
|
|
array of strings |
Yes |
The names of the actions to run, from List the available actions. At least one. On each package, they run in this order. |
|
|
Yes |
A query that finds the packages. The archive runs it again each time the schedule runs, so packages that match later are included. |
|
|
|
string |
Yes |
When to run, as a Quartz cron expression. See When a schedule runs. |
|
|
boolean |
No |
If |
{
"name": "Monthly fixity check",
"description": "Recalculates fixity for packages older than a year",
"plugins": ["fixityInformationPlugin"],
"criteria": {
"combinator": "AND",
"rules": [
{ "field": "dc:created", "operator": "OLDER_THAN", "value": "P1Y" }
]
},
"schedule": "0 0 3 1 * ?",
"enabled": true
}
Response: 201 Created with the PreservationSchedule.
-
400withREQUIRED_FIELD:name,plugins,criteria, orscheduleis missing. -
400withINVALID_CRON:scheduleisn't a valid cron expression. -
400: thecriteriaisn't valid. Thereasonsays which rule, as in Run actions on packages.
Update a schedule
Replaces the schedule with the body that you send. The body has the same fields as Create a schedule, so send all of them, not only the ones that change.
PUT /v2/preservation-action/schedules/{scheduleId}
Required role: archive-content-manager
Response: 200 OK with the updated PreservationSchedule.
-
404: there's no schedule with this ID. -
The
400errors of Create a schedule.
Delete a schedule
Deletes the schedule.
DELETE /v2/preservation-action/schedules/{scheduleId}
Required role: archive-content-manager
Response: 204 No Content.
-
404: there's no schedule with this ID.
Run a schedule now
Starts the schedule's actions on its packages straight away, whether or not the schedule is enabled.
POST /v2/preservation-action/schedules/{scheduleId}/run
Required role: archive-content-manager
Response: 202 Accepted with a BulkPreservationActionResult. To follow the run, see Follow a run.
-
404: there's no schedule with this ID.
Schemas
PreservationAction
|
Field |
Type |
Description |
|---|---|---|
|
|
string |
The name of the action. Use it in |
|
|
boolean |
Whether the action is enabled. |
|
|
integer |
Where the action comes in the archive's own sequence. The |
|
|
object |
The action's settings, as name and value pairs. Left out if the action has none. |
PreservationActionList
|
Field |
Type |
Description |
|---|---|---|
|
|
array of PreservationAction |
The actions. |
BulkPreservationActionResult
|
Field |
Type |
Description |
|---|---|---|
|
|
string |
The ID of the run. Use it to follow the run. |
|
|
string |
|
|
|
integer |
The number of packages in the run. |
|
|
integer |
The number of packages processed so far. |
|
|
integer |
The number of errors that the archive counted in the run. An action that fails on a package isn't counted. To see whether an action passed, check the execution reports. |
PreservationActionReport
|
Field |
Type |
Description |
|---|---|---|
|
|
string |
The name of the action. |
|
|
string |
The ID of the package. |
|
|
string |
|
|
|
string (date-time) |
When the action ran. |
|
|
string |
What the action reported. |
PreservationActionReportList
|
Field |
Type |
Description |
|---|---|---|
|
|
number |
The number of reports that match the filters. |
|
|
number |
The page number. |
|
|
number |
The page size. |
|
|
array of PreservationActionReport |
The reports in the page of results. |
PreservationSchedule
|
Field |
Type |
Description |
|---|---|---|
|
|
string |
The ID of the schedule. |
|
|
string |
The name of the schedule. |
|
|
string |
The description. |
|
|
array of strings |
The names of the actions that the schedule runs. |
|
|
The query that finds the packages. |
|
|
|
string |
When the schedule runs, as a Quartz cron expression. |
|
|
boolean |
Whether the schedule runs on its own. |
|
|
string (date-time) |
When the schedule was created. |
|
|
string (date-time) |
When the schedule was last changed. |
PreservationScheduleList
|
Field |
Type |
Description |
|---|---|---|
|
|
array of PreservationSchedule |
The schedules. |