Skip to content

Restore a version

restoreVersion

POST /api/v1/shares/{share_id}/versions/restore

Scope: files.overwriteRate cost: 5

Make an earlier version of a file its current contents again (one of listVersions’ ids)

Send If-Match with the file’s ETag as you last read it (428 without, 412 stale). Foldr’s own hosted storage copies the version over the file within the storage; other storage that keeps versions (S3, Azure, SharePoint, an SMB server’s shadow copies) is given that version’s bytes, proven whole, so a restore that fails leaves the file as it was. Needs files.overwrite, allowed for your app on this share; refused as replacing a file is (checked out, legal hold, out for signature, published to this reader). Answers the file with its new ETag. With as_copy true the version is instead written beside the file as a new file (“Report (3 Nov 2026 14.02).docx”, the first free name) and nothing is replaced: no If-Match is needed, it is answered 201 with the new file, and it is not counted against the allowance or held for approval. On an SMB share, restoring over a file that no shadow copy holds (it changed since the newest one) is refused 409 not-recoverable-here, because the overwrite would lose it: restore as a copy instead. Send an Idempotency-Key: the same request sent again with it answers the first answer. For an app whose administrator requires approval for its changes, it is not made at once: once every check has passed (and the items are counted against the allowance) it is answered 202 with an operation in state pending_approval, held for someone other than the person to approve in Foldr, then made as the person; poll it at its Location (getOperation). Refused 409 no-approver when nobody else could approve it.

Terminal window
curl -X POST "$FOLDR/api/v1/shares/$SHARE_ID/versions/restore" \
-H "Authorization: Bearer $TOKEN" \
-H "If-Match: $ETAG" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"path":"string","version_id":"string"}'

$FOLDR is your site’s address (for example https://files.example.com) and $TOKEN is an access token. See Getting access.

NameInTypeRequiredDescription
share_idpathstringYesThe share’s id.
If-MatchheaderstringYesThe file’s ETag as you last read it. ”*” is refused.
Idempotency-KeyheaderstringYesA value of your own, 1 to 255 visible ASCII characters, new for each new request. The same key with the same request within 24 hours answers the first answer again and restores nothing more; with a different request it is refused (422).

application/json, required: RestoreVersionBody

FieldTypeDescription
pathstringRequired. The path of the file.
version_idstringRequired. The version to restore: an id listVersions gave for this file.
as_copybooleantrue to write the version BESIDE the file as a new file named “name (3 Nov 2026 14.02).ext” (the first free name) and change nothing else. Needs no If-Match, is never refused for the file’s state (checked out, legal hold) and is not held for approval, because it replaces nothing. Default false: the version replaces the file.

Example:

{
"path": "string",
"version_id": "string"
}
StatusMeaningBody
200The file, with its new ETag.application/json: Item
201With as_copy: the new file, beside the original, with its ETag.application/json: Item
202Held for an approver (the app’s administrator requires approval for its changes): the operation, state pending_approval. Poll its Location after Retry-After seconds.application/json: Operation
HeaderDescription
ETagThe entity tag of what was answered. Send it back as If-None-Match for a 304 while it is unchanged, or as If-Match to change it only while it is unchanged.

Item:

FieldTypeDescription
share_idstring (uuid)Required. The id of the share the item is in.
pathstringRequired. The canonical path: as the storage holds it (its case), Unicode NFC, always starting with ”/”. ”/” is the top of the share. Send this form back in later calls.
namestringRequired. The item’s name (the last segment of its path; the share’s name for the top).
kindstring, one of file, folderRequired. file or folder.
sizeinteger or nullRequired. Size in bytes; null for a folder, and null when the item has no fixed byte size (a native Google document, exported on download: see export).
modifiedstring or null (date-time)Required. Last modified (RFC 3339, UTC), where the storage reports it.
mime_typestring or nullRequired. The item’s own media type, as the storage reports it or guessed from the name; null for a folder. A native Google document has Google’s own type here (application/vnd.google-apps.document for a Doc); export says what it downloads as.
exportExport or nullRequired. For a native Google document that can be downloaded, what content delivers: its media type and the extension the download is named with. Null for everything else, including a native Google type that cannot be downloaded (a Form: content answers 409 not-downloadable).
etagstring or nullRequired. The item’s entity tag: the storage’s own where it has one, else a weak tag over size and modified time (over modified time alone for a native Google document, whose export is made afresh each time). Null on a search hit, which comes from the index; GET …/item for the live one.
read_onlybooleanRequired. True when the person cannot change things in this share.
checked_outCheckout or nullRequired. Who has the item checked out, or null. Null on a search hit.

Example:

{
"share_id": "0191f2c4-8a1e-7b52-9d3a-5c1e0b7a4d21",
"path": "string",
"name": "string",
"kind": "file",
"size": 1,
"modified": "2026-11-04T09:30:00Z",
"mime_type": "string",
"export": {
"mime_type": "string",
"extension": "string"
},
"etag": "string",
"read_only": false,
"checked_out": {
"by": {},
"since": "2026-11-04T09:30:00Z"
}
}
HeaderDescription
ETagThe entity tag of what was answered. Send it back as If-None-Match for a 304 while it is unchanged, or as If-Match to change it only while it is unchanged.
LocationWhere to read what was made.

Item:

FieldTypeDescription
share_idstring (uuid)Required. The id of the share the item is in.
pathstringRequired. The canonical path: as the storage holds it (its case), Unicode NFC, always starting with ”/”. ”/” is the top of the share. Send this form back in later calls.
namestringRequired. The item’s name (the last segment of its path; the share’s name for the top).
kindstring, one of file, folderRequired. file or folder.
sizeinteger or nullRequired. Size in bytes; null for a folder, and null when the item has no fixed byte size (a native Google document, exported on download: see export).
modifiedstring or null (date-time)Required. Last modified (RFC 3339, UTC), where the storage reports it.
mime_typestring or nullRequired. The item’s own media type, as the storage reports it or guessed from the name; null for a folder. A native Google document has Google’s own type here (application/vnd.google-apps.document for a Doc); export says what it downloads as.
exportExport or nullRequired. For a native Google document that can be downloaded, what content delivers: its media type and the extension the download is named with. Null for everything else, including a native Google type that cannot be downloaded (a Form: content answers 409 not-downloadable).
etagstring or nullRequired. The item’s entity tag: the storage’s own where it has one, else a weak tag over size and modified time (over modified time alone for a native Google document, whose export is made afresh each time). Null on a search hit, which comes from the index; GET …/item for the live one.
read_onlybooleanRequired. True when the person cannot change things in this share.
checked_outCheckout or nullRequired. Who has the item checked out, or null. Null on a search hit.

Example:

{
"share_id": "0191f2c4-8a1e-7b52-9d3a-5c1e0b7a4d21",
"path": "string",
"name": "string",
"kind": "file",
"size": 1,
"modified": "2026-11-04T09:30:00Z",
"mime_type": "string",
"export": {
"mime_type": "string",
"extension": "string"
},
"etag": "string",
"read_only": false,
"checked_out": {
"by": {},
"since": "2026-11-04T09:30:00Z"
}
}
HeaderDescription
LocationWhere to poll the operation: GET it until it answers anything but 202.
Retry-AfterSeconds to wait before polling again.

Operation:

FieldTypeDescription
idstring (uuid)Required. The operation’s id.
kindstringRequired. What it does: copy, move (to another share, or held for approval within one), delete or restore (a version restore). delete and restore are only ever operations held for approval. Known values: copy, move, delete, restore. Clients must accept values not listed here.
statestring, one of pending_approval, queued, running, cancelling, succeeded, failed, cancelled, declined, expiredRequired. Where it has got to. pending_approval: held for an approver, nothing changed yet (approval says until when); queued: waiting to start; running: under way; cancelling: asked to stop, stopping at its next item; succeeded: done, result is what was made; failed: ended with the problem getOperation answers; cancelled: stopped, and what it had made removed (or, held for approval, withdrawn, nothing changed); declined: an approver said no, nothing changed; expired: nobody approved it in time, nothing changed.
phasestring or nullRequired. A move’s phase: copying (every item is copied first; nothing has been removed from where it was, and a cancel removes the partial copy), then deleting (the copy is whole and proven, and the originals are being removed: too late to cancel). Null for a copy. Known values: copying, deleting. Clients must accept values not listed here.
created_atstring (date-time)Required. When it was asked for (RFC 3339, UTC).
started_atstring or null (date-time)Required. When a worker first started it; null while queued.
finished_atstring or null (date-time)Required. When it finished; null until then.
sourceOperationSourceRequired. What is being copied, moved, deleted or restored.
targetOperationTarget or nullRequired. Where it was asked to go: the path asked for. result.path is where it landed (on_conflict “rename” may have given it another name). Null for a delete or a restore.
version_idstring or nullRequired. For a restore: the version asked for (one of listVersions’ ids). Null otherwise.
progressOperationProgressRequired. How far it has got.
resultItem or nullRequired. Once it has succeeded, what it made (the copy, the moved item at its new place, the restored file), at its canonical path; null until then, and for a delete (see deletion). A move that ended source-remains also has it: the whole copy it made.
deletionDeletion or nullRequired. A delete held for approval, once it has succeeded: what was deleted and where its storage keeps it now, as deleteItem answers. Null otherwise.
approvalOperationApproval or nullRequired. For an operation held for an approver: how its approval stands. Null for one that never waited for approval.
failuresarray of OperationFailureRequired. At most 100 items (failures_truncated says when there were more): for a copy that ended copy-incomplete, those it could not copy; for a move that ended source-remains, those still at the source. Empty otherwise.
failures_truncatedbooleanRequired. True when more items failed than failures lists.

Example:

{
"id": "0191f2c4-8a1e-7b52-9d3a-5c1e0b7a4d21",
"kind": "string",
"state": "pending_approval",
"phase": "string",
"created_at": "2026-11-04T09:30:00Z",
"started_at": "2026-11-04T09:30:00Z",
"finished_at": "2026-11-04T09:30:00Z",
"source": {
"share_id": "0191f2c4-8a1e-7b52-9d3a-5c1e0b7a4d21",
"path": "string",
"kind": "file"
},
"target": {
"share_id": "0191f2c4-8a1e-7b52-9d3a-5c1e0b7a4d21",
"path": "string"
},
"version_id": "string",
"progress": {
"items_done": 1,
"items_total": 1,
"bytes_done": 1,
"bytes_total": 1
},
"result": {
"share_id": "0191f2c4-8a1e-7b52-9d3a-5c1e0b7a4d21",
"path": "string",
"name": "string",
"kind": "file",
"size": 1,
"modified": "2026-11-04T09:30:00Z",
"mime_type": "string",
"export": {
"mime_type": "string",
"extension": "string"
},
"etag": "string",
"read_only": false,
"checked_out": {
"by": {},
"since": "2026-11-04T09:30:00Z"
}
},
"deletion": {
"deleted": {},
"items": 1,
"recoverable": "bin",
"destination": "string",
"where": "string"
},
"approval": {
"status": "string",
"expires_at": "2026-11-04T09:30:00Z",
"decided_at": "2026-11-04T09:30:00Z"
},
"failures": [
{
"path": "string",
"code": "string"
}
],
"failures_truncated": false
}

Every error is an application/problem+json document (ProblemDetails); branch on its type or code. See Errors.

StatusProblem typesWhen
400invalid-path
invalid-request
One of: Invalid path (invalid-path); Invalid request (invalid-request).
401invalid-tokenInvalid token (invalid-token).
403change-declined
insufficient-scope
legal-hold
write-not-allowed
One of: Change declined (change-declined); Insufficient scope (insufficient-scope); Legal hold (legal-hold); Not allowed for this app (write-not-allowed).
404not-foundNot found (not-found).
409ambiguous-path
change-expired
envelope-source
no-approver
not-a-file
not-recoverable-here
operation-cancelled
requester-not-connected
storage-account-not-connected
One of: Ambiguous path (ambiguous-path); Change not approved in time (change-expired); Out for signature (envelope-source); No approver (no-approver); Not a file (not-a-file); Not recoverable here (not-recoverable-here); Operation cancelled (operation-cancelled); Not connected when approved (requester-not-connected); Storage account not connected (storage-account-not-connected).
412changed-since-requested
precondition-failed
One of: Changed since requested (changed-since-requested); Precondition failed (precondition-failed).
413too-largeToo large (too-large).
422idempotency-key-reusedIdempotency key reused (idempotency-key-reused).
423checked-outChecked out (checked-out).
428precondition-requiredPrecondition required (precondition-required).
429destructive-budget
rate-limited
One of: Daily limit of removals reached (destructive-budget); Too many requests (rate-limited).
500internal-errorInternal error (internal-error).
503share-unavailable
share-unreachable
write-failed
One of: Share unavailable (share-unavailable); Share unreachable (share-unreachable); Write failed (write-failed).