Skip to content

Revisions

List the revisions behind a stable link, label them, roll back by promoting an earlier revision, and delete revisions you no longer need.

On this page

Every time a file gets new bytes, SteadyLink keeps the old bytes as a revision and makes the new one current. The file's asset ID and link never change; the link simply serves whichever revision is current. Use these endpoints to see a file's history, annotate it, undo a bad replacement in one request, and clean up revisions that take up storage.

Revisions belong to a file, so every route here takes the file's asset ID (the ID in https://cdn.steadylink.io/a/{asset_id}), not the bucket ID. Revisions are addressed by their versionNumber: 1 for the first upload, then 2, 3, and so on.

The JavaScript examples assume const steadylink = new SteadyLink({ apiKey: process.env.STEADYLINK_API_KEY! }) and the Python examples assume client = SteadyLink(api_key=os.environ["STEADYLINK_API_KEY"]).

How revisions are created#

A new revision is created when:

The new revision becomes current. The previous ones stay retained, and each counts toward the workspace's storage until you delete it. Revisions are immutable: you can label them, promote them, or delete them, but never change their bytes.

A revision is delivered only after its malware scan is clean. While a current revision is still scanning, the link answers 423. See Delivery.

EndpointMethod and pathScope
List revisionsGET /api/assets/{asset_id}/versionsassets:read
Label a revisionPATCH /api/assets/{asset_id}/versions/{version}assets:write
Promote a revisionPOST /api/assets/{asset_id}/versions/{version}/promoteassets:write
Delete a revisionDELETE /api/assets/{asset_id}/versions/{version}assets:write

Operations#

List revisions#

GET/api/assets/{asset_id}/versions
Requiresassets:read

Returns every retained revision, newest first, as a JSON array. There is no pagination.

curl "https://api.steadylink.io/api/assets/3f2a9c1e-8b4d-4c7a-a1e2-6d5f0b9c3e71/versions" \
  -H "X-API-Key: $STEADYLINK_API_KEY"
200 OKResponse
[
  {
    "versionNumber": 4,
    "storageKey": "assets/3f2a9c1e-8b4d-4c7a-a1e2-6d5f0b9c3e71/versions/4/hero-v2.webp",
    "byteSize": 2950112,
    "width": 2400,
    "height": 1600,
    "mime": "image/webp",
    "hash": "c47e1d9a0b3f62e8d5a9f1c0b7e4d2a68f3c9e1b0d7a5f2c8e6b4d1a9f0c3e7b",
    "id": "5d8a2f1c-7e3b-4a90-b6c4-e0f9d2a1b738",
    "label": "Launch approved",
    "note": "Final color correction from the agency",
    "createdBy": null,
    "isCurrent": true,
    "scanStatus": "clean",
    "metadataStatus": "complete",
    "createdAt": "2026-10-08T15:10:44.391027"
  },
  {
    "versionNumber": 3,
    "storageKey": "assets/3f2a9c1e-8b4d-4c7a-a1e2-6d5f0b9c3e71/versions/3/hero.webp",
    "byteSize": 2841024,
    "width": 2400,
    "height": 1600,
    "mime": "image/webp",
    "hash": "9b2e6f0c4a7d18e3b5f2c9a0d6e4b7f1a3c8e2d5f0b9a6c4e7d1f3b8a2c5e9d0",
    "id": "e4d7b1a9-2c6f-4083-9a5e-1b8d3f0c6e27",
    "label": null,
    "note": null,
    "createdBy": "1a7c4e92-8b3d-4f06-a5e1-c2d9b0f7e384",
    "isCurrent": false,
    "scanStatus": "clean",
    "metadataStatus": "complete",
    "createdAt": "2026-10-01T09:02:18.775310"
  }
]

Response fields

versionNumberinteger
The revision's number. Use it in ?v= delivery URLs and in the routes below.
iduuid
The revision's own ID. Webhooks and some responses call it revisionId.
isCurrentboolean
true for the revision the stable link serves. Exactly one revision is current while any exist.
hashstring
SHA-256 of the bytes. Compare hashes to see whether two revisions are identical.
byteSizeinteger
Stored size. Every retained revision counts toward storage.
width, heightinteger | null
Pixel dimensions for images, otherwise null.
label, notestring | null
Your annotations. See Label a revision.
createdByuuid | null
The user who created the revision. null for revisions created with an API key, through an upload batch, or by an automated workflow.
scanStatusstring | null
pending, clean, infected, or error. null when scanning is off.
metadataStatusstring
pending, processing, complete, or error.

A file ID from another workspace returns 403, and an unknown ID returns 404 Asset not found. A bucket ID returns an empty array.

Label a revision#

PATCH/api/assets/{asset_id}/versions/{version}
Requiresassets:write

Sets the human-readable label and note on one revision, for example to record who approved it. Both fields are written on every call: a field you omit is cleared. Send the current value of the other field if you only want to change one.

Body

labelstring | null
Short label, up to 120 characters, such as Launch approved. Empty or whitespace-only clears it.
notestring | null
Longer note, up to 1000 characters. Empty or whitespace-only clears it.
curl -X PATCH "https://api.steadylink.io/api/assets/3f2a9c1e-8b4d-4c7a-a1e2-6d5f0b9c3e71/versions/4" \
  -H "X-API-Key: $STEADYLINK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "label": "Launch approved", "note": "Final color correction from the agency" }'
200 OKResponse
{
  "id": "5d8a2f1c-7e3b-4a90-b6c4-e0f9d2a1b738",
  "versionNumber": 4,
  "label": "Launch approved",
  "note": "Final color correction from the agency"
}

A label longer than 120 characters or a note longer than 1000 returns 400 Validation error. A revision number that does not exist returns 404 Revision not found.

Promote a revision#

POST/api/assets/{asset_id}/versions/{version}/promote
Requiresassets:write

Makes an existing revision current. This is how you roll back: promote the last good revision and the stable link serves it again. Promotion does not copy bytes or create a new revision, so it is instant and uses no extra storage. You can promote forward again later; nothing is lost.

curl -X POST "https://api.steadylink.io/api/assets/3f2a9c1e-8b4d-4c7a-a1e2-6d5f0b9c3e71/versions/3/promote" \
  -H "X-API-Key: $STEADYLINK_API_KEY"
200 OKResponse
{
  "promoted": true,
  "versionNumber": 3,
  "revisionId": "e4d7b1a9-2c6f-4083-9a5e-1b8d3f0c6e27"
}
StatusMessageCause
404Revision not foundNo revision with that number. Revision numbers are per file; list them first.
409Only clean revisions can be promotedThe revision's scan is still pending, or it ended infected or error. Only clean revisions can become current.

After a promotion, SteadyLink's own lookups switch immediately, but browsers and shared caches can keep serving the previous revision for up to five minutes. URLs pinned with ?v= are unaffected. See Caching.

To make a revision current at a future time, with an optional automatic rollback, use scheduled revisions.

Delete a revision#

DELETE/api/assets/{asset_id}/versions/{version}
Requiresassets:write

Permanently deletes one revision's bytes and its cached image variants, and releases its storage.

Query parameters

forcebooleanDefault false
Required to delete the current revision. Without it, deleting the current revision returns 400 Cannot delete current version without force=true.
curl -X DELETE "https://api.steadylink.io/api/assets/3f2a9c1e-8b4d-4c7a-a1e2-6d5f0b9c3e71/versions/2" \
  -H "X-API-Key: $STEADYLINK_API_KEY"
200 OKResponse
{ "deleted": true }

What happens next depends on which revision you delete:

  • An older revision. It disappears from the list. URLs pinned to it with ?v= return 404 once caches expire.
  • The current revision, with force=true. The highest-numbered remaining revision becomes current, even if it is not the one that was current before. Promote a different one afterwards if needed.
  • The last remaining revision. The file itself is deleted: its listing, its asset ID, and its link all go away, as with Delete a file.

An unknown revision number returns 404 Version not found.

Next steps#