API Reference

The examples below use the Compose stack's local address, http://localhost:5001. Note that the service serves its own OpenAPI specification at /docs.

Note

POST /v1/ro_crates/validate_metadata is always available, but the storage-backed endpoints are only available when the service runs with STORAGE_ENABLED=true (see Installation & Setup); without this set, POST /v1/ro_crates/{crate_id}/validation or GET /v1/ro_crates/{crate_id}/validation requests will return a 404 result.

Validate metadata

POST /v1/ro_crates/validate_metadata

This validates the contents of an ro-crate-metadata.json document and returns the result in the response.

Field Required Description
crate_json yes The metadata document, as a JSON string
profile_name no Profile to validate against, e.g. ro-crate-1.2. The validator will default to ro-crate-1.1 when this is omitted

Warning

Currently, the validation profile is not detected from the RO-Crate. In other words, a conformsTo declaration in the metadata does not influence which validation profile is used by the validator, and the validation always runs against profile_name, or ro-crate-1.1 when it is omitted.

To validate an ro-crate metadata file:

jq -Rs '{crate_json: .}' ro-crate-metadata.json | curl -X POST http://localhost:5001/v1/ro_crates/validate_metadata -H 'Content-Type: application/json' -d @-

To choose a profile, add it to the json object as a profile_name entry:

jq -Rs '{crate_json: ., profile_name: "ro-crate-1.2"}' ro-crate-metadata.json | curl -X POST http://localhost:5001/v1/ro_crates/validate_metadata -H 'Content-Type: application/json' -d @-
Code Meaning
200 Validated; the result has a status of valid or invalid
422 crate_json is either missing, empty or invalid, or the validation could not run (an error result)

Validate a stored RO-Crate

POST /v1/ro_crates/{crate_id}/validation

This queues validation of an RO-Crate held in the object store. The RO-Crate is resolved first, so a missing or ambiguous crate ID may be reported immediately; the validation process itself runs asynchronously on a worker.

Note

See Crate IDs for how {crate_id} maps to objects in the bucket.

Field Required Description
profile_name no Profile to validate against; defaults to ro-crate-1.1 when omitted
webhook_url no URL that receives the result when validation finishes
curl -X POST http://localhost:5001/v1/ro_crates/my-dataset-2026/validation -H 'Content-Type: application/json' -d '{"profile_name": "ro-crate-1.2"}'
Code Meaning
202 Queued; the body is {"message": "Validation in progress"}
400 Invalid Crate ID
404 Either storage mode is not enabled, or there is no RO-Crate at the location defined by the given Crate ID
409 Both a zip and a directory exist for this Crate ID
422 Request body invalid
503 Object store unreachable

Fetch a validation result

GET /v1/ro_crates/{crate_id}/validation

This returns the stored result for an RO-Crate.

curl http://localhost:5001/v1/ro_crates/my-dataset-2026/validation
Code Meaning
200 The stored result, including persisted error results
400 Invalid Crate ID
404 No result stored for this Crate ID

Validation results

Every validation produces a result object:

{
  "status": "invalid",
  "profile": "ro-crate-1.2",
  "created_at": "2026-07-22T10:30:00+00:00",
  "detail": {}
}

An RO-Crate's status can be:

status Meaning
valid The RO-Crate conforms to the profile
invalid The RO-Crate does not conform to the profile, issues listed in detail field
error The validation could not run; the reason is in an error field. No detail field is provided

Note

detail contains the complete validation report. created_at is the UTC time of a stored-crate validation, and null for metadata-only validation, which does not set it. profile is the requested profile name, or null when the default (ro-crate-1.1) was used.

For stored RO-Crates the same object is saved to {S3_RESULTS_PREFIX}/<id>.json and returned by the GET endpoint.

Webhooks

If webhook_url was given, the worker POSTs the result object to it as JSON once validation finishes. The result is saved to the store first and the webhook sent after, so a notification is never sent for a result that was not stored.

Note that delivery is attempted three times, waiting 0.5s then 1s between attempts, with a 10s timeout per attempt.

Crate IDs

A Crate ID is the label in the URL path that identifies an RO-Crate in the object store: the service looks for {S3_CRATE_PREFIX}/<id>.zip (zip) or {S3_CRATE_PREFIX}/<id>/ (directory). Crate IDs must match ^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$: they start with a letter or digit, may contain letters, digits, ., _ and -, and are at most 128 characters long. Anything else is rejected with 400.

Health

GET /healthz reports that the process is up, and always returns 200 {"status": "ok"}. GET /readyz checks the object store and Celery broker, returning 200 when ready and 503 otherwise, with the individual checks in the body. When storage is off, both checks report disabled.