Skip to Content
SimulatorsDropbox changelog

Simulators

Dropbox changelog

What changed in each Dropbox simulator release, newest first.

v0.0.5 — 2026-11-05

  1. The webhook notifies the member on a mount, an unmount or a change of access level. mount_folder, unmount_folder, and the owner’s update_folder_member that changes a mounted member’s access level each POST one notification naming that member alone, as Dropbox does. share_folder of an existing folder no longer notifies its owner, since Dropbox sends nothing for it.

  2. Moving the clock past a webhook retry sends it at once. A failed notification still waits its 10 s to 320 s backoff on the wall clock, and POST /_rystic/clock past a retry’s due now sends it straight away; a retry waiting out its delay no longer refuses a new notification as queue_full. The delivery report on GET /_rystic/egress adds retries_armed, next_retry_at and next_retry_clock.

  3. A request with no access token is refused on every route as Dropbox refuses it. Before it reads the arguments the twin answers 400 text/plain, Error in call to API function "<route>": Invalid authorization value in HTTP header/URL parameter, or on most content routes that line in a JSON envelope tagged other, where it answered 401 invalid_access_token. An empty Bearer or another scheme gets the same 400, apart from Basic, which Dropbox reads as app authentication.

  4. A state dump seeds back as it was, and the next record gets a fresh id. GET /_rystic/inspect posted to POST /_rystic/seed after a reset restores every record where it was, per-caller records included, which used to land under a doubled key. The next record created after any seed passes every uuid and event id the simulator minted that the seed holds. GET /_rystic/inspect?view=sequences lists every id counter, and a world document’s new sequences key restores them, so ids the simulator renders from a counter continue where the dump left off.

  5. A slow client no longer holds up the others. The simulator reads a request’s whole body before it starts serving it and sends the answer after, so a client that uploads slowly, or reads a large answer slowly, no longer delays other clients’ requests. Answers are unchanged; one larger than 4 MiB still makes other requests wait while it is sent.

  6. The call log shows what each call asked for and whether it succeeded. Each GET /_rystic/calls entry now carries args, the call’s query and body arguments with credentials redacted (long values cut, file contents left out), and ok, false for an answer that is not 2xx. A batch upload answered at HTTP 200 whose first entry failed is not ok either. A path the simulator does not serve is marked unknown_route: true. ?tail=N returns only the last N calls, and dropped counts the calls the log no longer keeps.

  7. The docs are one page, with a page per feature. The archive ships README.md in place of HOWTO.md and SCENARIOS.md, with the same sections in the same order as every Rystic simulator’s page, and CHANGELOG.md beside it. Upload sessions and batches, listings and the change feed, deleted files and revisions, shared folders and file members, shared links and file requests, and tags each have their own page under docs/features/, and every example on these pages runs as written against a fresh simulator.

  8. The docs page links the admin token section. The page now sends you to the admin token’s section of the shared-simulators page.

  9. Scenario descriptions use customer terms. The Scenarios table and --list-scenarios describe each scenario in American spelling, with no internal references.

  10. The Scenarios table is easier to scan. Each row says in a line what the scenario is for, and a list below the table says what each scenario holds.

  11. Pro starts with a 14-day trial. Free has ended, so every simulator is on Pro and Enterprise, and the docs name only those plans.

  12. Limitations is shorter to read. It opens with the known issues and one sentence counting the rest. The detailed lists follow, and the website folds them behind “Show all limitations”.

  13. The webhooks section names every answer of the URL route. It lists what the POST refuses with 400, the 200 a set URL returns, the fields GET returns and the 204 DELETE returns.

  14. The page has no Plans section. The Quickstart names the plans that run the simulator, and the pricing page lists what each plan includes.

  15. The docs read more plainly, mark each difference from Dropbox where it’s described and keep only the simulator’s own facts. Sentences are shorter, and each behavior that differs from Dropbox, such as the long poll’s missing jitter or the 150 MiB upload-session cap, carries a “Differs from Dropbox” line beside it. How each route takes its argument, what a write does over an existing path, which webhook notifications each request sends and what an upload session does with a wrong offset are tables. files/get_preview is listed with the download routes, which return their result in the Dropbox-API-Result header and also take the arg query parameter. Seeding, sign-in and reset keep only what is particular to this simulator, such as its registers and their keys, and link the shared pages for the rest.

v0.0.4 — 2026-10-15

  1. Swagger UI to read and call the twin from the browser. /_rystic/swagger, linked from the state UI header, is Swagger UI over the published API trimmed to the operations this twin serves; Try it out sends each request to the twin.

v0.0.3 — 2026-10-15

  1. Uploads up to 150 MiB per request. files/upload, upload_session/start and upload_session/append_v2 take bodies up to 150 MiB, the limit Dropbox documents per request, where anything over 1 MiB answered 413 or, mid-session, 409 too_large; the SDKs’ 4 MiB chunked uploads now run end to end. A file, uploaded whole or through a session, holds at most 150 MiB on the twin.

  2. Batch sharing reads answer per-file errors, and a malformed cursor answers 409. sharing/get_file_metadata/batch and sharing/list_file_members/batch answer 200 with an access_error (invalid_file for a path naming nothing, is_folder for a folder) on the entry it concerns, instead of failing the whole call with 500, and order a mixed answer as Dropbox does: errors first for file metadata, member lists first for members. A cursor that is not a cursor at all, such as "bogus", answers 409 invalid_cursor on file_requests/list/continue and 409 reset on sharing/list_shared_links, which ignored it; a well-formed cursor that names no position still answers 500 text/plain, as does any bad cursor on sharing/list_received_files/continue, as Dropbox does.

  3. add_folder_member with no access_level adds a viewer. An entry that omits access_level now joins the shared folder as a viewer, Dropbox’s default, instead of an editor.

  4. A finished member removal warns in Dropbox’s words. sharing/check_remove_member_job_status answers complete with the warning text Dropbox sends.

  5. Seeded folders carry folder fields only. Folders and deleted folders in the shipped worlds no longer carry rev, size, is_downloadable, content_hash, client_modified or server_modified, fields Dropbox sends on files only.

  6. An upload session’s finish writes as files/upload does. files/upload_session/finish of the bytes a file already holds answers that file unchanged, keeping its rev, where it answered 409 under mode add and minted a new rev under overwrite; strict_conflict and a stale update rev still answer path/conflict/file. A commit.path beneath a file answers path/conflict/file_ancestor, a folder there path/conflict/folder in every mode, a commit.path ending in / path/malformed_path, and a mode WriteMode does not name 400, where each was stored or overwritten.

  7. Batch moves and copies refuse what a single move or copy refuses. An entry of files/move_batch_v2 or files/copy_batch_v2 whose to_path is /, ends in /, or lies beneath a file is that entry’s failure in the job’s result — relocation_error to/malformed_path or to/conflict/file_ancestor — and nothing is written for it, where the batch moved or copied it there; and a batch-moved file’s rev comes from the same sequence as every other write’s.

  8. create_folder_v2 refuses a path ending in /, and three sharing errors read as Dropbox’s. files/create_folder_v2 of / or of a path ending in / answers 409 path/malformed_path and creates nothing, where it created the folder without the slash or answered conflict/folder. sharing/mount_folder’s already_mounted and sharing/unmount_folder’s access_error/unmounted carry Dropbox’s user_message, and sharing/list_file_members/batch answers an unknown file ID’s 500 as plain text, not a JSON string.

  9. A write into a missing folder creates the folder. An upload, an upload session’s finish, a copy, a move, their batch forms and a save_url job into a path whose parent folders do not exist now create each missing parent, as Dropbox does, so files/get_metadata reads them as folders and files/list_folder lists them; you no longer need create_folder_v2 first.

  10. Dropbox-API-Path-Root is checked against the caller’s account. If the root or namespace the header names is not the account’s root or home namespace, the request now answers 422 invalid_root with the account’s root_info. A value that is not a JSON root selector answers 400. Before this change both were ignored. home, the account’s root namespace and its home namespace still answer from the account’s own files.

  11. A shared folder is one folder in every member’s Dropbox. A member who mounts a share lists the owner’s files, and an upload, move, copy or delete by any member reaches the owner and every other member. files/get_metadata, list_folder and search report sharing_info on a shared folder and everything inside it, with read_only true for a viewer, and share_folder on an already shared folder answers bad_path/already_shared. In dropbox_team_shared and dropbox_paired_identity the seeded shares resolve on get_folder_metadata and list_folders for every member, and both Acme members list /Acme Inc Team Folder.

  12. File members belong to the file, not its path. Two accounts that each hold a file at the same path keep their own file members and sharing settings, and a file keeps its members through a move or rename.

  13. list_folder/continue is Dropbox’s change feed, and files/list_folder/longpoll is served. After a list_folder listing, or from a get_latest_cursor cursor, continue answers each path written below the cursor’s folder since the cursor, once, in its final state: deleted for a deleted or moved-away path, and the entry for a created, copied, moved-in or overwritten one, the deleted and folder entries first and then the files. Before, a cursor was a position in the current listing, so a delete, a move, an overwrite and a name that sorts earlier never reached it. A cursor is never used up, its limit carries to every page, and sharing a folder under it lists the folder again. files/list_folder/longpoll takes no Authorization header, as on notify.dropboxapi.com. It answers {"changes": true} once a write lands in the namespace of the cursor’s folder, or at once if one already has, and {"changes": false} after timeout seconds.

  14. The twin sends Dropbox’s webhook. Boot it with RYSTIC_WEBHOOK_DELIVERY=on and POST /_rystic/webhooks {"url", "secret"}: once your endpoint echoes the GET ?challenge= handshake, every write to a file or folder POSTs {"delta":{"users":[<uid>]},"list_folder":{"accounts":["<account_id>"]}}, naming the writer, or every account that has the shared folder mounted, signed X-Dropbox-Signature with your secret. Reads send nothing, and a failed notification is retried on Dropbox’s documented backoff. Each seeded account carries a synthetic uid. Mounting, unmounting and changing a member’s access send nothing yet, where Dropbox names the member.

v0.0.2 — 2026-10-13

  1. files/list_folder/continue renders entries as the first page does. A folder on a continuation page carries the folder fields only, never a file’s rev, size, content_hash or timestamps, and a folder carries its property_groups on both pages, as Dropbox does.

  2. users/get_space_usage reports the account’s files. used is the total size of the account’s files, rising with an upload and falling with a delete, and the allocation is an individual 2,147,483,648 bytes, the Basic plan’s, where it answered 0 and 0.

  3. The shipped worlds’ accounts and files read like Dropbox’s. Every world account ID is Dropbox’s 40-character dbid: form, so users/get_account and get_account_batch find a world’s own account, and every seeded file downloads size bytes whose block digest is its content_hash and restores from its rev. The large seeded files are smaller than before: a world now carries the bytes it declares.

  4. Void results are null, and unset optional fields are left out. sharing/revoke_shared_link, files/upload_session/append_v2 and sharing/unshare_file answer the JSON literal null instead of an empty body, and files/search/continue_v2 and file_requests/update leave out an optional field the result does not hold instead of rendering it as null, so a strict JSON client reads them as Dropbox renders them.

  5. Listing a deleted folder answers path/not_found. files/list_folder on the path of a folder you deleted answers 409 path/not_found, as Dropbox does; path/not_folder now means the path is a file.

  6. A shared link serves its file’s bytes. sharing/get_shared_link_file answers the file’s bytes, a file you uploaded included, where it answered an empty body.

  7. Member changes take effect. add_folder_member and add_file_member by email add the account that holds the address, or list an invitee when none does; a member demoted to viewer gets no_write_permission on upload, create and delete inside the share and reads it read_only: true; remove_folder_member, relinquish_folder_membership and unshare_folder take the folder out of the member’s Dropbox, and an unshared folder can be shared again; a file’s members follow it through a move.

  8. Deleting a copied folder deletes its contents. files/delete_v2 of a folder made by files/copy_v2 answers it as a folder and removes the copied files with it; each copied file has its own rev, and copy_v2 answers is_downloadable.

  9. Shared links follow their file. A second create_shared_link_with_settings answers shared_link_already_exists carrying the existing link’s metadata; a link follows its file through a move and goes with it on delete; a password without link_password, or an expiry in the past, answers settings_error/invalid_settings on a Pro account; and get_shared_link_file on a folder link answers shared_link_is_directory.

  10. Downloads take ?arg= and Range. The download routes read their argument from the arg query parameter when the Dropbox-API-Arg header is absent; files/download and sharing/get_shared_link_file answer a byte Range with 206 and Content-Range.

  11. Batch moves and deletes act as their one-entry routes. A folder moved by files/move_batch_v2 takes its contents with it, and a moved file keeps its members and shared links at its new path; files/delete_batch leaves a tombstone, deletes a folder’s contents with it and removes the deleted file’s shared links, as files/move_v2 and files/delete_v2 do.

  12. Batch copies carry their bytes and their folder’s contents. A file copied by files/copy_batch_v2 downloads its source’s bytes under a rev of its own, and a folder it copies arrives with everything beneath it, as with files/copy_v2.

  13. Six sharing errors carry Dropbox’s user_message. add_file_member and remove_file_member_2 on an invalid file, relinquish_folder_membership on an invalid share, and mount_folder, relinquish_folder_membership and update_folder_policy by a non-member answer user_message {locale, text} beside the error, as Dropbox does.

  14. A deleted entry reads as DeletedMetadata, and downloads as not found. files/get_metadata with include_deleted: true answers a deleted entry with only .tag, name, path_lower and path_display, as Dropbox does, and files/download of a deleted path answers 409 path/not_found instead of path/not_file.

  15. A deleted file lists its revisions and restores. files/list_revisions on a file you deleted answers its revisions with is_deleted: true and server_deleted, instead of 409 path/not_file, so a recover-a-deleted-file flow can pick a rev and pass it to files/restore; mode also takes the bare tag ("id"). The dropbox_deleted_backlog world’s four deleted files now list and restore too.

  16. A rename keeps a file’s revision history. files/move_v2 and files/move_batch_v2 give a moved file a new rev, as Dropbox does, and files/list_revisions in id mode lists the file’s revisions from before and after the rename.

  17. Search renders a folder as a folder. files/search_v2 and files/search/continue_v2 answer a folder without a file’s rev, size, content_hash or timestamps, and neither kind with is_restorable, as files/list_folder renders them.

  18. Three more sharing errors carry Dropbox’s user_message. add_folder_member with a malformed dropbox_id, remove_file_member_2 of a file’s owner and update_folder_policy on an unknown share answer user_message {locale, text} beside the error, as Dropbox does.

v0.0.1 — 2026-10-13

  1. A local Dropbox for your integration and the agents that drive it. The first release of the Dropbox twin: 88 operations of the Dropbox API v2 — one account’s files and folders, listings and search with their cursors, shared links, file requests, shared folders and file members, upload sessions, batch jobs and save_url, and tags — served on one port for both api.dropboxapi.com and content.dropboxapi.com, from a model validated against a live Dropbox account. Point the official JavaScript SDK at it through a fetch that rewrites the two hosts, or curl it with any bearer token (HOWTO.md shows both); nothing reaches Dropbox and no real account changes.

  2. Files and folders, created, uploaded and read back. files/create_folder_v2, get_metadata, list_folder, move_v2, copy_v2, delete_v2, get_temporary_link, list_revisions and restore take a JSON body; files/upload and download take their argument in the Dropbox-API-Arg header beside the bytes, as on the content host, and download answers the file’s metadata in Dropbox-API-Result. A path that holds nothing answers 409 path/not_found, a create or an add-mode upload over an existing entry 409 path/conflict, and autorename lands the upload as name (1). A malformed path answers as Dropbox does: one that fails a route’s path pattern answers the 400 plain-text input error, and one ending in a trailing slash answers 409 malformed_path, on download, delete_v2 and get_metadata. Every upload, session finish and restore records its own rev. Every folder create_folder_v2 creates has its own id, and each account holds its own files: a second account reading the first one’s unshared folder gets path/not_found, while a file shared with it reaches it through sharing/list_received_files and get_file_metadata.

  3. Listings and search page by cursor, as Dropbox’s do. The cursor files/list_folder answers resumes the listing through list_folder/continue, for a folder addressed by path or by id:, and get_latest_cursor hands out the cursor for a folder’s current state, whatever property templates include_property_groups names; a limit outside 1 to 2000 answers the 400 input error, and the cursor of a deleted folder answers 409 path/not_found. files/search_v2 matches the words of a name, case-insensitively, scoped by options.path; a max_results smaller than the matches answers a standard-base64 cursor that search/continue_v2 walks, and a cursor the twin never handed out answers 400.

  4. Shared links, file requests, shared folders and file members. sharing/create_shared_link_with_settings mints a www.dropbox.com link, refusing a password on a Basic account with 409 settings_error/not_authorized as Dropbox does, that list_shared_links, get_shared_link_metadata and modify_shared_link_settings read and change, get_shared_link_file downloads through, and revoke_shared_link ends. file_requests/create opens a request at a destination folder; a list/continue cursor that is not a live file-requests listing position answers 500 text/plain, as Dropbox does; delete refuses an open one with 409 file_request_open until update closes it, and count, list, list_v2 and delete_all_closed cover the account’s requests. sharing/add_file_member gives an account access to a file, which list_file_members lists and get_file_metadata reports; the account that calls share_folder is the share’s owner, so list_folders and list_mountable_folders list it, get_folder_metadata and list_folder_members answer it with access_type owner and unshare_folder launches its job; add_folder_member, mount_folder and the folder-member routes are served, and a mounted share lands in the member’s own Dropbox at the path_lower the mount answered. No email is sent for any of them.

  5. Large files in pieces, folders as a zip, and batch jobs that complete on the second check. files/upload_session/start, append_v2 and finish commit a file’s bytes in order, and an append whose cursor.offset differs from the bytes held answers 409 incorrect_offset with correct_offset. A second finish of a finished session at the held offset commits its bytes again at the new commit.path, at any other offset it answers 409 lookup_failed/incorrect_offset, and an append_v2 after finish answers 409 closed; a session ID the twin never minted answers 500 text/plain, as Dropbox does, and another account’s 409 lookup_failed/not_found. start_batch, append_batch and finish_batch_v2 do the same for many sessions. download_zip answers a folder as application/zip with its metadata in Dropbox-API-Result. save_url, copy_batch_v2, move_batch_v2 and delete_batch answer an async_job_id whose check answers in_progress first and complete on the next check, or once the clock has moved two seconds past the launch, as measured on Dropbox; create_folder_batch answers complete inline. Once a save_url job answers complete, get_metadata and list_folder show its file at the job’s path and download answers its bytes, a placeholder derived from the URL, since save_url fetches nothing.

  6. Tags on a file or folder. files/tags/add, tags/get and tags/remove add, read and remove a file’s or a folder’s tags; tags/get answers each path’s tags as user_generated_tag entries, removing a tag the entry does not carry answers 409 tag_not_present, and a tag_text outside lower-case letters, digits and underscores answers 500, as Dropbox does.

  7. Five shipped Dropboxes. --scenario dropbox_personal_archive boots Ada Sealy’s Pro account and a nine-entry tree with revs, hashes and sizes, the world check.sh and the quickstart use. dropbox_fresh_signup holds an unverified Basic account and only /Apps, dropbox_deleted_backlog five deleted entries listed as tombstones beside one surviving file, dropbox_paired_identity a personal account paired with a Northwind work account, each with its own tree, and dropbox_team_shared two Acme members with their own tokens (sl.rosa-desktop, sl.toni-laptop), a shared team folder and a timeline the clock plays: Toni creates /Drafts, uploads a sketch and shares it with Rosa, then Rosa files her scratch note and deletes /Scratch. SCENARIOS.md says what each is for. POST /_rystic/seed lands accounts, entries, revisions, links, requests and shares directly, and POST /_rystic/reset rewinds the sequences and the clock, so two identical runs give byte-identical entries.

  8. Measured against a live Dropbox account. The full-suite round of 2026-10-12 (20261012T232831Z) matched 214 of 246 probes against a live Dropbox account, with 19 inconclusive: the sharing-member probes Dropbox’s daily invite cap leaves rate-limited, which the round scores inconclusive rather than failed. HOWTO.md states the differences this release ships with: a missing Authorization header and Dropbox’s text/plain error bodies are answered as JSON, the twin’s 500 answers are not compared against Dropbox, files/tags/get by a folder’s id is unmeasured, and search matches names only, never a file’s content.

Last updated on