Simulators
Dropbox changelog
What changed in each Dropbox simulator release, newest first.
v0.0.5 — 2026-11-05
-
The webhook notifies the member on a mount, an unmount or a change of access level.
mount_folder,unmount_folder, and the owner’supdate_folder_memberthat changes a mounted member’s access level each POST one notification naming that member alone, as Dropbox does.share_folderof an existing folder no longer notifies its owner, since Dropbox sends nothing for it. -
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/clockpast a retry’s due now sends it straight away; a retry waiting out its delay no longer refuses a new notification asqueue_full. Thedeliveryreport onGET /_rystic/egressaddsretries_armed,next_retry_atandnext_retry_clock. -
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 taggedother, where it answered 401invalid_access_token. An emptyBeareror another scheme gets the same 400, apart fromBasic, which Dropbox reads as app authentication. -
A state dump seeds back as it was, and the next record gets a fresh id.
GET /_rystic/inspectposted toPOST /_rystic/seedafter 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=sequenceslists every id counter, and a world document’s newsequenceskey restores them, so ids the simulator renders from a counter continue where the dump left off. -
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.
-
The call log shows what each call asked for and whether it succeeded. Each
GET /_rystic/callsentry now carriesargs, the call’s query and body arguments with credentials redacted (long values cut, file contents left out), andok, 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 markedunknown_route: true.?tail=Nreturns only the last N calls, anddroppedcounts the calls the log no longer keeps. -
The docs are one page, with a page per feature. The archive ships
README.mdin place ofHOWTO.mdandSCENARIOS.md, with the same sections in the same order as every Rystic simulator’s page, andCHANGELOG.mdbeside 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 underdocs/features/, and every example on these pages runs as written against a fresh simulator. -
The docs page links the admin token section. The page now sends you to the admin token’s section of the shared-simulators page.
-
Scenario descriptions use customer terms. The Scenarios table and
--list-scenariosdescribe each scenario in American spelling, with no internal references. -
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.
-
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.
-
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”.
-
The webhooks section names every answer of the URL route. It lists what the
POSTrefuses with 400, the 200 a set URL returns, the fieldsGETreturns and the 204DELETEreturns. -
The page has no Plans section. The Quickstart names the plans that run the simulator, and the pricing page lists what each plan includes.
-
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_previewis listed with the download routes, which return their result in theDropbox-API-Resultheader and also take theargquery 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
- 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
-
Uploads up to 150 MiB per request.
files/upload,upload_session/startandupload_session/append_v2take bodies up to 150 MiB, the limit Dropbox documents per request, where anything over 1 MiB answered 413 or, mid-session, 409too_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. -
Batch sharing reads answer per-file errors, and a malformed cursor answers 409.
sharing/get_file_metadata/batchandsharing/list_file_members/batchanswer 200 with anaccess_error(invalid_filefor a path naming nothing,is_folderfor 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 409invalid_cursoronfile_requests/list/continueand 409resetonsharing/list_shared_links, which ignored it; a well-formed cursor that names no position still answers 500 text/plain, as does any bad cursor onsharing/list_received_files/continue, as Dropbox does. -
add_folder_memberwith noaccess_leveladds a viewer. An entry that omitsaccess_levelnow joins the shared folder as a viewer, Dropbox’s default, instead of an editor. -
A finished member removal warns in Dropbox’s words.
sharing/check_remove_member_job_statusanswerscompletewith thewarningtext Dropbox sends. -
Seeded folders carry folder fields only. Folders and deleted folders in the shipped worlds no longer carry
rev,size,is_downloadable,content_hash,client_modifiedorserver_modified, fields Dropbox sends on files only. -
An upload session’s finish writes as
files/uploaddoes.files/upload_session/finishof the bytes a file already holds answers that file unchanged, keeping itsrev, where it answered 409 under modeaddand minted a newrevunderoverwrite;strict_conflictand a staleupdaterev still answerpath/conflict/file. Acommit.pathbeneath a file answerspath/conflict/file_ancestor, a folder therepath/conflict/folderin every mode, acommit.pathending in/path/malformed_path, and a modeWriteModedoes not name 400, where each was stored or overwritten. -
Batch moves and copies refuse what a single move or copy refuses. An entry of
files/move_batch_v2orfiles/copy_batch_v2whoseto_pathis/, ends in/, or lies beneath a file is that entry’s failure in the job’s result —relocation_errorto/malformed_pathorto/conflict/file_ancestor— and nothing is written for it, where the batch moved or copied it there; and a batch-moved file’srevcomes from the same sequence as every other write’s. -
create_folder_v2refuses a path ending in/, and three sharing errors read as Dropbox’s.files/create_folder_v2of/or of a path ending in/answers 409path/malformed_pathand creates nothing, where it created the folder without the slash or answeredconflict/folder.sharing/mount_folder’salready_mountedandsharing/unmount_folder’saccess_error/unmountedcarry Dropbox’suser_message, andsharing/list_file_members/batchanswers an unknown file ID’s 500 as plain text, not a JSON string. -
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_urljob into a path whose parent folders do not exist now create each missing parent, as Dropbox does, sofiles/get_metadatareads them as folders andfiles/list_folderlists them; you no longer needcreate_folder_v2first. -
Dropbox-API-Path-Rootis 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 422invalid_rootwith the account’sroot_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. -
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_folderand search reportsharing_infoon a shared folder and everything inside it, withread_onlytrue for a viewer, andshare_folderon an already shared folder answersbad_path/already_shared. Indropbox_team_sharedanddropbox_paired_identitythe seeded shares resolve onget_folder_metadataandlist_foldersfor every member, and both Acme members list/Acme Inc Team Folder. -
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.
-
list_folder/continueis Dropbox’s change feed, andfiles/list_folder/longpollis served. After alist_folderlisting, or from aget_latest_cursorcursor,continueanswers each path written below the cursor’s folder since the cursor, once, in its final state:deletedfor 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, itslimitcarries to every page, and sharing a folder under it lists the folder again.files/list_folder/longpolltakes noAuthorizationheader, as onnotify.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}aftertimeoutseconds. -
The twin sends Dropbox’s webhook. Boot it with
RYSTIC_WEBHOOK_DELIVERY=onandPOST /_rystic/webhooks {"url", "secret"}: once your endpoint echoes theGET ?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, signedX-Dropbox-Signaturewith your secret. Reads send nothing, and a failed notification is retried on Dropbox’s documented backoff. Each seeded account carries a syntheticuid. Mounting, unmounting and changing a member’s access send nothing yet, where Dropbox names the member.
v0.0.2 — 2026-10-13
-
files/list_folder/continuerenders entries as the first page does. A folder on a continuation page carries the folder fields only, never a file’srev,size,content_hashor timestamps, and a folder carries itsproperty_groupson both pages, as Dropbox does. -
users/get_space_usagereports the account’s files.usedis 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. -
The shipped worlds’ accounts and files read like Dropbox’s. Every world account ID is Dropbox’s 40-character
dbid:form, sousers/get_accountandget_account_batchfind a world’s own account, and every seeded file downloadssizebytes whose block digest is itscontent_hashand restores from itsrev. The large seeded files are smaller than before: a world now carries the bytes it declares. -
Void results are
null, and unset optional fields are left out.sharing/revoke_shared_link,files/upload_session/append_v2andsharing/unshare_fileanswer the JSON literalnullinstead of an empty body, andfiles/search/continue_v2andfile_requests/updateleave out an optional field the result does not hold instead of rendering it asnull, so a strict JSON client reads them as Dropbox renders them. -
Listing a deleted folder answers
path/not_found.files/list_folderon the path of a folder you deleted answers 409path/not_found, as Dropbox does;path/not_foldernow means the path is a file. -
A shared link serves its file’s bytes.
sharing/get_shared_link_fileanswers the file’s bytes, a file you uploaded included, where it answered an empty body. -
Member changes take effect.
add_folder_memberandadd_file_memberby email add the account that holds the address, or list an invitee when none does; a member demoted to viewer getsno_write_permissionon upload, create and delete inside the share and reads itread_only: true;remove_folder_member,relinquish_folder_membershipandunshare_foldertake 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. -
Deleting a copied folder deletes its contents.
files/delete_v2of a folder made byfiles/copy_v2answers it as a folder and removes the copied files with it; each copied file has its ownrev, andcopy_v2answersis_downloadable. -
Shared links follow their file. A second
create_shared_link_with_settingsanswersshared_link_already_existscarrying the existing link’s metadata; a link follows its file through a move and goes with it on delete; a password withoutlink_password, or an expiry in the past, answerssettings_error/invalid_settingson a Pro account; andget_shared_link_fileon a folder link answersshared_link_is_directory. -
Downloads take
?arg=andRange. The download routes read their argument from theargquery parameter when theDropbox-API-Argheader is absent;files/downloadandsharing/get_shared_link_fileanswer a byteRangewith 206 andContent-Range. -
Batch moves and deletes act as their one-entry routes. A folder moved by
files/move_batch_v2takes its contents with it, and a moved file keeps its members and shared links at its new path;files/delete_batchleaves a tombstone, deletes a folder’s contents with it and removes the deleted file’s shared links, asfiles/move_v2andfiles/delete_v2do. -
Batch copies carry their bytes and their folder’s contents. A file copied by
files/copy_batch_v2downloads its source’s bytes under arevof its own, and a folder it copies arrives with everything beneath it, as withfiles/copy_v2. -
Six sharing errors carry Dropbox’s
user_message.add_file_memberandremove_file_member_2on an invalid file,relinquish_folder_membershipon an invalid share, andmount_folder,relinquish_folder_membershipandupdate_folder_policyby a non-member answeruser_message {locale, text}beside the error, as Dropbox does. -
A deleted entry reads as
DeletedMetadata, and downloads as not found.files/get_metadatawithinclude_deleted: trueanswers a deleted entry with only.tag,name,path_lowerandpath_display, as Dropbox does, andfiles/downloadof a deleted path answers 409path/not_foundinstead ofpath/not_file. -
A deleted file lists its revisions and restores.
files/list_revisionson a file you deleted answers its revisions withis_deleted: trueandserver_deleted, instead of 409path/not_file, so a recover-a-deleted-file flow can pick arevand pass it tofiles/restore;modealso takes the bare tag ("id"). Thedropbox_deleted_backlogworld’s four deleted files now list and restore too. -
A rename keeps a file’s revision history.
files/move_v2andfiles/move_batch_v2give a moved file a newrev, as Dropbox does, andfiles/list_revisionsinidmode lists the file’s revisions from before and after the rename. -
Search renders a folder as a folder.
files/search_v2andfiles/search/continue_v2answer a folder without a file’srev,size,content_hashor timestamps, and neither kind withis_restorable, asfiles/list_folderrenders them. -
Three more sharing errors carry Dropbox’s
user_message.add_folder_memberwith a malformeddropbox_id,remove_file_member_2of a file’s owner andupdate_folder_policyon an unknown share answeruser_message {locale, text}beside the error, as Dropbox does.
v0.0.1 — 2026-10-13
-
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 bothapi.dropboxapi.comandcontent.dropboxapi.com, from a model validated against a live Dropbox account. Point the official JavaScript SDK at it through afetchthat rewrites the two hosts, or curl it with any bearer token (HOWTO.mdshows both); nothing reaches Dropbox and no real account changes. -
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_revisionsandrestoretake a JSON body;files/uploadanddownloadtake their argument in theDropbox-API-Argheader beside the bytes, as on the content host, anddownloadanswers the file’s metadata inDropbox-API-Result. A path that holds nothing answers 409path/not_found, a create or an add-mode upload over an existing entry 409path/conflict, andautorenamelands the upload asname (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 409malformed_path, ondownload,delete_v2andget_metadata. Every upload, session finish and restore records its ownrev. Every foldercreate_folder_v2creates has its ownid, and each account holds its own files: a second account reading the first one’s unshared folder getspath/not_found, while a file shared with it reaches it throughsharing/list_received_filesandget_file_metadata. -
Listings and search page by cursor, as Dropbox’s do. The cursor
files/list_folderanswers resumes the listing throughlist_folder/continue, for a folder addressed by path or byid:, andget_latest_cursorhands out the cursor for a folder’s current state, whatever property templatesinclude_property_groupsnames; alimitoutside 1 to 2000 answers the 400 input error, and the cursor of a deleted folder answers 409path/not_found.files/search_v2matches the words of a name, case-insensitively, scoped byoptions.path; amax_resultssmaller than the matches answers a standard-base64 cursor thatsearch/continue_v2walks, and a cursor the twin never handed out answers 400. -
Shared links, file requests, shared folders and file members.
sharing/create_shared_link_with_settingsmints awww.dropbox.comlink, refusing a password on a Basic account with 409settings_error/not_authorizedas Dropbox does, thatlist_shared_links,get_shared_link_metadataandmodify_shared_link_settingsread and change,get_shared_link_filedownloads through, andrevoke_shared_linkends.file_requests/createopens a request at a destination folder; alist/continuecursor that is not a live file-requests listing position answers 500 text/plain, as Dropbox does;deleterefuses an open one with 409file_request_openuntilupdatecloses it, andcount,list,list_v2anddelete_all_closedcover the account’s requests.sharing/add_file_membergives an account access to a file, whichlist_file_memberslists andget_file_metadatareports; the account that callsshare_folderis the share’s owner, solist_foldersandlist_mountable_folderslist it,get_folder_metadataandlist_folder_membersanswer it withaccess_typeowner andunshare_folderlaunches its job;add_folder_member,mount_folderand the folder-member routes are served, and a mounted share lands in the member’s own Dropbox at thepath_lowerthe mount answered. No email is sent for any of them. -
Large files in pieces, folders as a zip, and batch jobs that complete on the second check.
files/upload_session/start,append_v2andfinishcommit a file’s bytes in order, and an append whosecursor.offsetdiffers from the bytes held answers 409incorrect_offsetwithcorrect_offset. A secondfinishof a finished session at the held offset commits its bytes again at the newcommit.path, at any other offset it answers 409lookup_failed/incorrect_offset, and anappend_v2after finish answers 409closed; a session ID the twin never minted answers 500 text/plain, as Dropbox does, and another account’s 409lookup_failed/not_found.start_batch,append_batchandfinish_batch_v2do the same for many sessions.download_zipanswers a folder asapplication/zipwith its metadata inDropbox-API-Result.save_url,copy_batch_v2,move_batch_v2anddelete_batchanswer anasync_job_idwhose check answersin_progressfirst andcompleteon the next check, or once the clock has moved two seconds past the launch, as measured on Dropbox;create_folder_batchanswerscompleteinline. Once asave_urljob answerscomplete,get_metadataandlist_foldershow its file at the job’s path anddownloadanswers its bytes, a placeholder derived from the URL, sincesave_urlfetches nothing. -
Tags on a file or folder.
files/tags/add,tags/getandtags/removeadd, read and remove a file’s or a folder’s tags;tags/getanswers each path’s tags asuser_generated_tagentries, removing a tag the entry does not carry answers 409tag_not_present, and atag_textoutside lower-case letters, digits and underscores answers 500, as Dropbox does. -
Five shipped Dropboxes.
--scenario dropbox_personal_archiveboots Ada Sealy’s Pro account and a nine-entry tree with revs, hashes and sizes, the worldcheck.shand the quickstart use.dropbox_fresh_signupholds an unverified Basic account and only/Apps,dropbox_deleted_backlogfive deleted entries listed as tombstones beside one surviving file,dropbox_paired_identitya personal account paired with a Northwind work account, each with its own tree, anddropbox_team_sharedtwo 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.mdsays what each is for.POST /_rystic/seedlands accounts, entries, revisions, links, requests and shares directly, andPOST /_rystic/resetrewinds the sequences and the clock, so two identical runs give byte-identical entries. -
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.mdstates the differences this release ships with: a missingAuthorizationheader and Dropbox’s text/plain error bodies are answered as JSON, the twin’s 500 answers are not compared against Dropbox,files/tags/getby a folder’sidis unmeasured, and search matches names only, never a file’s content.