Browse, search, read, upload, and share the user's Dropbox — including team/shared folders — through per-user OAuth.
87%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
Low
Low-risk findings worth noting
Use this skill when the user asks about their Dropbox files or folders — listing, searching, reading/downloading, uploading, or sharing.
This is an OAuth connector. The resolved user's Dropbox token already lives on your computer as an environment variable, one per Dropbox API host (the way a logged-in CLI's cached credential would):
$VAULT_TOKEN_API_DROPBOXAPI_COM — for api.dropboxapi.com (RPC: list, search, share, move, delete)$VAULT_TOKEN_CONTENT_DROPBOXAPI_COM — for content.dropboxapi.com (download, upload)Both carry the same Dropbox token (one OAuth grant spans every host), so if a
host-specific var is empty, $VAULT_TOKEN_API_DROPBOXAPI_COM works as the bearer for any
Dropbox host. Pass it as -H "Authorization: Bearer $VAULT_TOKEN_..." on every call;
nothing on the network path adds it for you. Never ask the user
for a token, log it, or use another principal's credential or a service fallback.
If $VAULT_TOKEN_API_DROPBOXAPI_COM is empty: per-user connector tokens are injected
only in a direct DM with the user (their personal scope) — in a channel or group
they're absent by design, even for a fully-connected user. So don't tell a channel user to
reconnect; ask them to DM you to run this. Only if it's empty inside a DM does it mean they
haven't connected Dropbox — then point them to the Connectors page.
On 400 Invalid authorization value: the header was missing or empty, so Dropbox
never checked the token. Fix your command (echo ${#VAULT_TOKEN_API_DROPBOXAPI_COM} shows
the variable is set) and retry; this says nothing about the user's connection. Before
telling a user Dropbox is broken, confirm with users/get_current_account below.
On 401 (invalid_access_token, expired_access_token): the token was sent and
rejected → have them reconnect — unless the error body's
.tag is missing_scope, in which case the app lacks a permission; name the required_scope
it returns (the connected app grants account_info.read, files.metadata.read,
files.content.read/write, sharing.read/write).
This is the step that makes team and shared folders visible. By default the Dropbox
API only lists the user's personal (home) namespace — for a Business member that root
is often nearly empty. The team folders they see in the Dropbox web UI live in the
team namespace, and the API only shows them when you set the Dropbox-API-Path-Root
header.
Resolve the account's namespaces once, then reuse the root_namespace_id for the rest of
the session — it doesn't change. This endpoint takes no arguments: send no request body
and no Content-Type (adding Content-Type: application/json with an empty body returns
a 400):
curl -sS -X POST 'https://api.dropboxapi.com/2/users/get_current_account' \
-H "Authorization: Bearer $VAULT_TOKEN_API_DROPBOXAPI_COM"Read root_info from the response. If root_info[".tag"] is team, use its
root_namespace_id to see everything (team folders + the member's own files); if it is
user (individual account), the default root is fine and no header is needed.
When you have a root_namespace_id, add this header to every files/sharing call so
your view matches the web UI (substitute the id):
-H 'Dropbox-API-Path-Root: {".tag":"root","root":"ROOT_NAMESPACE_ID"}'Prefer referencing items by id ("id:...", returned by list/search) over path
strings — ids are stable across namespaces and avoid path-escaping issues.
path is "" for the root of the active namespace, or a folder path/id:
curl -sS -X POST 'https://api.dropboxapi.com/2/files/list_folder' \
-H "Authorization: Bearer $VAULT_TOKEN_API_DROPBOXAPI_COM" \
-H 'Dropbox-API-Path-Root: {".tag":"root","root":"ROOT_NAMESPACE_ID"}' \
-H 'Content-Type: application/json' \
--data '{"path":"","recursive":false}'For an ls -R-style or find-across-a-tree request, set "recursive":true to stream the
whole subtree in one paginated pass instead of walking folder by folder.
If the response has "has_more":true, page with the returned cursor:
curl -sS -X POST 'https://api.dropboxapi.com/2/files/list_folder/continue' \
-H "Authorization: Bearer $VAULT_TOKEN_API_DROPBOXAPI_COM" \
-H 'Content-Type: application/json' \
--data '{"cursor":"CURSOR"}'curl -sS -X POST 'https://api.dropboxapi.com/2/files/search_v2' \
-H "Authorization: Bearer $VAULT_TOKEN_API_DROPBOXAPI_COM" \
-H 'Dropbox-API-Path-Root: {".tag":"root","root":"ROOT_NAMESPACE_ID"}' \
-H 'Content-Type: application/json' \
--data '{"query":"budget","options":{"max_results":100}}'If the response has "has_more": true, keep fetching with its cursor via
files/search/continue_v2 (same shape as list_folder/continue above) before
concluding a file doesn't exist.
Downloads use the content host and carry their argument in the Dropbox-API-Arg header
(no JSON body). Reference the file by id or path:
curl -sS -X POST 'https://content.dropboxapi.com/2/files/download' \
-H "Authorization: Bearer $VAULT_TOKEN_CONTENT_DROPBOXAPI_COM" \
-H 'Dropbox-API-Path-Root: {".tag":"root","root":"ROOT_NAMESPACE_ID"}' \
-H 'Dropbox-API-Arg: {"path":"id:FILE_ID"}' \
-o inbox/dropbox-file.binKeep source paths/ids in your answer so claims can be traced.
Uploading, sharing, moving, and deleting are writes. Prepare the exact change, name the target file/folder (id + path), and get approval before running it.
Upload bytes you produced (content host; the arg is a header, the file is the body):
curl -sS -X POST 'https://content.dropboxapi.com/2/files/upload' \
-H "Authorization: Bearer $VAULT_TOKEN_CONTENT_DROPBOXAPI_COM" \
-H 'Dropbox-API-Path-Root: {".tag":"root","root":"ROOT_NAMESPACE_ID"}' \
-H 'Dropbox-API-Arg: {"path":"/Reports/q3.pdf","mode":"add","autorename":true}' \
-H 'Content-Type: application/octet-stream' \
--data-binary @q3.pdfCreate a shared link (returns a url; a 409 shared_link_already_exists carries the
existing link in its metadata — reuse it):
curl -sS -X POST 'https://api.dropboxapi.com/2/sharing/create_shared_link_with_settings' \
-H "Authorization: Bearer $VAULT_TOKEN_API_DROPBOXAPI_COM" \
-H 'Dropbox-API-Path-Root: {".tag":"root","root":"ROOT_NAMESPACE_ID"}' \
-H 'Content-Type: application/json' \
--data '{"path":"id:FILE_ID"}'Move/rename or delete (delete_v2 is recoverable — the file goes to the user's deleted files, not a permanent purge):
curl -sS -X POST 'https://api.dropboxapi.com/2/files/move_v2' \
-H "Authorization: Bearer $VAULT_TOKEN_API_DROPBOXAPI_COM" \
-H 'Dropbox-API-Path-Root: {".tag":"root","root":"ROOT_NAMESPACE_ID"}' \
-H 'Content-Type: application/json' \
--data '{"from_path":"id:FILE_ID","to_path":"/Archive/q3.pdf"}'
curl -sS -X POST 'https://api.dropboxapi.com/2/files/delete_v2' \
-H "Authorization: Bearer $VAULT_TOKEN_API_DROPBOXAPI_COM" \
-H 'Dropbox-API-Path-Root: {".tag":"root","root":"ROOT_NAMESPACE_ID"}' \
-H 'Content-Type: application/json' \
--data '{"path":"id:FILE_ID"}'Always report the file path/id and what changed, plus any shared link you created.
yc-software/qm
88c380f
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.