Skip to main content
Once an account is connected, moving files takes three calls:
  1. Browse to let the user choose a folder
  2. Transfer to create the link and start a run
  3. Poll or subscribe to follow progress

Step 1: Browse the provider

Browse returns one level at a time. With no parameters you get the top-level containers: matters for Clio and Smokeball, My Drive and shared drives for Google Drive, All Files for Box, and the account’s root for Dropbox.
Endpoint
cURL
Response
To descend, pass back the browse_ref fields from the item the user picked:
cURL
Item kind is one of my_drive, shared_drive, matter, folder, or file. The gated Microsoft OneDrive and SharePoint provider also returns site and document_library, and is the only provider that uses the site parameter.
browse_ref and import_ref are opaque references. Pass them back exactly as received.Never construct one from a provider id supplied by a browser, and never accept one as user input in your own API. These values are how the service decides what a caller is allowed to reach.
Some items are browsable but not importable, and some are the reverse. When an item carries an import_ref that differs from its browse_ref, use import_ref as the link’s remote.
Browsing needs a connection scope that permits server-side listing. If it does not, you get 403 provider_scope_insufficient—the user consented at a narrower tier than browsing requires.

Search instead of browsing

When the user knows what they want but not where it is, search the connection. Search uses the provider’s own search, returns files by default, and works across the whole account or inside one folder. Box, Clio, Dropbox and Google Drive support search; Smokeball does not.
Endpoint
cURL
Response
Each provider in GET /connectors/v1/connections lists its search capability, and each connection reports search_supported. Read them before showing a search box:
  • full_text is false when the provider may match file names only.
  • folder_scope_recursive is false when a folder scope covers that folder’s direct children only (Google Drive). A shared drive’s container scope still searches the whole drive.
  • kinds lists what the provider can search for. A provider without search answers 422 search_not_supported; a kind it cannot search answers 422 search_kind_not_supported; a scope it cannot honor answers 422 search_scope_not_supported.
Search shares the connection’s request budget with browsing and background runs, and throttles the same way: 429 with Retry-After when known.

Find a folder anywhere

Pass kind=folder to find folders by name, however deep they sit. Each result carries a browse_ref to open it with browse, and a display path from the top of the account. Google Drive, Box and Dropbox search folders; Clio does not.
cURL
Response
Folders match by name only, so full_text is always false. Box paths start below All Files, Dropbox paths at the account root (/Smith/Discovery/Exhibits), and Google Drive paths at My Drive or the shared drive’s name. A Google Drive folder shared with the user starts at the highest folder they can see. Google Drive reports parents rather than paths, so each folder search there also looks up the results’ ancestors and spends more of the request budget. When the user already has the folder open in the provider, let them paste its link. Resolve returns the folder as a browse item: pass its browse_ref fields to browse to open it, or use it as the transfer root.
Endpoint
cURL
Response
path is set when the provider reports it in the same lookup (Box, Dropbox, and Microsoft when Graph includes the parent path). Resolving reads the link; it never accepts a share or adds the folder to the account.

Fetch one file instead of importing a folder

When the user needs one file now, not a folder kept in sync, fetch it. Each file item from browse or search carries an open_ref: a signed reference bound to your organization, installation, subject and connection. Pass it back exactly as received. It is null for folders and for providers without single-file fetch (Box, Dropbox, Google Drive and Clio support it).
Endpoint
cURL
Response (201)
  • Destination: exactly one of vault_id, or upload_url, a presigned HTTPS Amazon S3 PUT URL. Leave Content-Type out of the URL’s signed headers; the file’s type is sent as an unsigned header.
  • Size: up to 100 MB, copied within the request. Larger files return 413 fetch_too_large; import their folder with a transfer instead.
  • Repeats: fetching the same provider version to the same destination returns the first copy with 200 and reused: true, without downloading again. A concurrent identical request gets 409 fetch_in_progress with Retry-After.
  • Indexing: a Vault copy is stored like a finished upload. Call POST /vault/{id}/ingest/{object_id} to index it.
  • Exports: links never export a fetched copy, just as they never export an imported one.
  • Errors: an unknown or out-of-scope reference returns 404. Items the import engine would skip (a Box note, a Google Form) return 422 fetch_unsupported_item, and a provider without single-file fetch returns 422 fetch_not_supported. When the presigned URL refuses the upload, you get 502 upload_url_rejected.

Preview what a folder will import

Before the user starts an import, show what it will bring in. Contents lists every file under one folder, at any depth, as a flat paginated list, so you can show a file count and list without walking subfolders yourself.
Endpoint
cURL
Response
  • Paths: each path is relative to the folder you listed and ends in the file’s name.
  • Pages: a page comes back as soon as it holds files, so it can be shorter than page_size while cursor is still set. Show each page as it arrives and keep requesting until cursor is null.
  • Limit: a listing stops after 10,000 files with truncated: true. A very wide Google Drive or Box tree can also end early with truncated: true. Show the count as a minimum (“10,000+ files”).
  • Skipped files: unsupported_reason marks files an import would skip, such as a Box note or a Google Form.
  • Providers: Google Drive, Box and Dropbox, plus Microsoft OneDrive and SharePoint where it is enabled. Clio and Smokeball answer 422 contents_not_supported; fall back to browsing.
Contents runs only when you call it, for the folder you name. It shares the connection’s request budget with browsing and background runs and throttles the same way: 429 with Retry-After when known.
Endpoint
cURL
Response (202)
A link’s identity is (connection_id, direction, remote, vault_id), plus selection for partial exports. The first call creates it and runs a full backfill. Every later call with the same values runs an incremental diff against the ledger—so “Re-import” in your UI is this exact request again. If a run is already active, the existing run is returned instead of an error. Double-clicking is safe.

Exclude folders or files

For Clio and Google Drive document imports, include policy.filters.exclude_folder_ids and policy.filters.exclude_file_ids with stable provider IDs from browsing. Excluding a folder excludes its entire subtree. New files in included folders continue importing, while these exclusions apply to subsequent runs and full reconciliations. Existing vault copies are preserved. Exclusions require policy.deletes: "preserve" (the default); combining exclusions with deletes: "mirror" returns 400. For direction: "both", exclusions are stored on the import half only; the export half retains other policy settings. Each list accepts up to 1,000 IDs. The import root cannot be excluded. These filters do not apply to exports, Clio tasks, or Clio communications. Connections advertise support through import_exclusions_supported: true. An existing source link keeps its selection. Repeating a transfer with a different selection returns 409 import_selection_conflict; use the link policy update endpoint to deliberately change an existing link’s filters. PATCH /connectors/v1/links/{id} replaces the entire stored policy. Include every policy field you want to retain, including deletes, collisions, and existing size/MIME filters. Omitted fields return to their defaults; PATCH does not merge policy objects.

Export part of a vault

An export sends every exportable file in the vault by default. To send only some of them, add selection to a direction: "export" request:
  • object_ids exports up to 5,000 listed vault objects. Each keeps its full vault path under the destination, so your folder layout is preserved. IDs that are not in vault_id return 400 selection_objects_not_found with data.error.count.
  • folder exports that vault folder and everything below it. Paths are relative to the selected folder: its files land directly in remote, and its subfolders become subfolders there. The vault root is not a selection; omit selection instead.
  • Both together export the listed objects that are inside the folder, with folder-relative paths.
Selected files are still skipped while they are processing and when they were imported or fetched from a provider. The selection is part of the link’s identity: exporting /A and then /B to the same destination creates two links, and repeating a selection re-runs its link. selection with direction import or both returns 400 selection_requires_export. Links return their selection, or null for a whole-vault export.

Export into a new folder

When the destination folder does not exist yet, create it first, then export into it. Name the parent with the same site, container and parent fields browse accepts; for Clio and Smokeball, a matter’s root is the browse_ref the matter itself returned.
Endpoint
cURL
Response (201)
Use the folder’s browse_ref fields as the export remote (folder_id, plus container_id and site_id when present). name is trimmed and must be 1 to 255 characters, with no /, \ or control characters, and not . or ... If a folder with that name is already directly under the parent, you get that folder back with 200 and "status": "existing" instead of a duplicate. Dropbox, Box, Microsoft and Smokeball match names ignoring case; Google Drive and Clio match them exactly. Smokeball creates folders asynchronously. The request waits up to about ten seconds for the new folder to appear. If it has not appeared by then, the response is 202 with "status": "pending", "code": "folder_creation_pending" and a null folder. Repeat the request after a short wait: once Smokeball lists the folder, you get it back with 200 and "status": "existing". Smokeball has no way to create a folder only once, so a repeat sent while the folder is still not listed asks for it again and can leave two folders with that name. Space repeats out rather than retrying in a tight loop. Providers advertise this with supports_create_folder in the connections list. Google Drive, Dropbox, Box and Clio support it. Microsoft and Smokeball support it where their exports are enabled, and only for connections authorized with write access.

When the destination already has the file

policy.collisions decides what an export does when the destination folder already holds a file with the same name that the export did not write. An export always recognizes its own earlier copy, by the provider file it recorded or the marker it put on that file, and updates it. Running or resuming the same export again never adds another copy. version names are the same on every provider. A folder can hold up to 100 kept copies of one name; past that, the file fails with connector_export_destination_conflict. Any other collisions value returns 400.

When a run does not start

run.started can be false with a reason. This is not an error: The link is created either way. Poll it and the run will begin.

When the request is refused

Keeping a folder current

For a standing promise instead of a one-shot, use /sync-link. Same body, minus run_mode.
Endpoint
It backfills now, then stays current on a sweep cycle. Due links run incrementally about every 15 minutes. Once a day the sweep runs a full reconcile instead, which catches deletions and moved folders that per-file change feeds cannot report. An existing once link is upgraded in place, keeping its ledger and cursor. Nothing re-imports. To step back down or pause:
cURL
PATCH also accepts state (paused or ready) and a replacement policy.

Step 3: Follow progress

Endpoint
Response
A run that fails because the provider was rate-limiting or temporarily unavailable does not need attention: the link returns to ready and the sweep retries it on its own, waiting 15 minutes after the first failure and doubling after each consecutive one, up to a day. retry_at shows the earliest retry; a manual sync does not wait for it. Only a permanent failure, or ten consecutive failures in a row, lands in error.

Run statuses

running, completed, completed_with_errors, or failed. completed_with_errors means the run finished and some files failed—check the ledger for which.
counts.pending is the umbrella for everything not yet settled. queued and processing are subsets of it, so do not add them together.

Per-file results

Run stats tell you how many. The ledger tells you which.
Endpoint
cURL
Each row carries the provider item, the vault object it became, its path, its content version, its state, and an error when one applies. Filter by state and page with cursor.

Events instead of polling

For anything longer than a few seconds, subscribe rather than poll. These events carry connector progress: All connector events require the connectors scope on your webhook endpoint. run.progress moves through two stages. discovering means the provider folder is still being listed, and found counts the files seen so far. copying means files are being transferred, and stats counts what has been added, updated, skipped and failed. recentPaths holds up to 20 paths of files copied since the previous event. Events can arrive out of order, so ignore one whose sequence is lower than the last you saw for that run. The run ends with run.completed or run.failed.
Endpoint
Deletes the link and its ledger. Vault documents are kept by default. Add ?vault_docs=delete to remove the documents an import link brought in. That cleanup runs as a durable background workflow and returns 202.
vault_docs=delete is not reversible. Confirm with the user before calling it.

Next steps

Errors & Recovery

What each failure means and which ones to retry

Providers

How providers differ in hierarchy, change detection, and rate budget

Vault Search

Search the documents once they have been ingested