putUpload file
Can overwrite or deletefiles:write
Upload a file (or files) and get a public URL plus GitHub-ready markdown. Files on disk and a shell to run curl? Use sign_upload_url instead, which skips base64. Prefer the returned embedUrl in GitHub markdown. All uploads are public. Pass pr+repo to attach to a PR (stable key + managed comment, which updates itself and shows each image's screen, state and caption). A result with holdCheck: "pending" may still be held for review if it shows a secret; comment.held counts files on the PR or issue held for review; see list_held. Pass branch+repo to stage for a PR that does not exist yet; if that branch already has one open PR (repo linked to this workspace), the file attaches to it instead. This server has no git, so in a checkout read repo and branch from git and always pass them. When the bytes are already at a public HTTPS URL, pass contentUrl instead of base64 — the server fetches them. Accepts images (PNG, JPEG, GIF, WebP, AVIF), video (MP4, WebM, MOV), PDF, zip, gzip, and text (plain, markdown, CSV, JSON). SVG and XML are accepted only on storage lanes verified to serve them sandboxed (see the workspace's storage settings); HTML is rejected.
Returns workspacekeyurlembedUrlsizecontentTypereplacedmarkdownprovenancemetadatavisibilityholdCheckfileuploadsfailurescommentcommentErrorpromotionpromoteErroroptimizeframedryRunhint
| Parameter | Type | Description |
|---|
contentBase64 | string | Base64-encoded file content to upload (must be non-empty). Exactly one of contentBase64, contentUrl, or files is required. |
|---|
contentUrl | string | Public HTTPS URL of an already-hosted file to fetch and re-host. Filename is optional when the URL path has a leaf. No auth headers are forwarded; private/internal hosts are rejected. Exactly one of contentBase64, contentUrl, or files is required. |
|---|
filename | string | Filename for the content (drives the key and content type). Required with contentBase64; optional with contentUrl when the URL path has a leaf. |
|---|
files | object[] | Multiple files in one call (max 20). Each item needs contentBase64 or contentUrl. Filename is optional with contentUrl when the URL path has a leaf. Cannot combine with contentBase64, contentUrl, filename, or key. |
|---|
key | string | Override the object key. Cannot combine with pr/issue/branch. |
|---|
prefix | string | Key prefix for the default key layout (default: screenshots). |
|---|
repo | string | GitHub owner/name. Required with pr/issue/branch. Optional otherwise (default: misc). This server has no git: in a checkout, read it with git remote get-url origin. |
|---|
ref | string | Optional key segment (default: today). Cannot combine with pr/issue/branch. |
|---|
pr | number | Attach to this pull request (stable gh/ key). Mutually exclusive with issue. Requires repo. With branch, also promotes that branch's staged files. |
|---|
issue | number | Attach to this issue (stable gh/ key). Mutually exclusive with pr and branch. Requires repo. |
|---|
branch | string | Git branch (git branch --show-current). Stages under it, or attaches to its open PR when the repo is linked to this workspace and exactly one is open. With pr, also promote this branch's staged files into the PR. Requires repo. |
|---|
comment | boolean | With pr or issue: create or update the managed attachments comment after upload. Default true. Pass false to skip. A comment failure never fails the upload. |
|---|
alt | string | Alt text for the markdown (default: filename). |
|---|
width | number | Emit <img width=…> markdown instead of a plain image embed. |
|---|
metadata | object | Queryable tags for later search (key→value). Use path for the route (e.g. /settings), not route/page. Omit to leave existing tags; pass an object (even {}) to replace them. state, app, screen and caption have their own fields. On pr/issue/branch, gh.* is set for you. |
|---|
state | "before" | "after" | "empty" | "error" | "loading" | The UI state this image shows. Set it whenever the image is one side of a comparison — before/after is the most useful pair in a PR, and is what makes find_files with state=after work later. |
|---|
app | string | Which surface is shown: web, ios, android, cli. Worth setting only when the same route exists on more than one surface. |
|---|
screen | string | The app screen shown, for views with no route (a mobile or desktop screen), e.g. "Chat". Shown under the image in the PR comment. Use path in metadata for web routes. |
|---|
caption | string | What the shot shows, in plain words (up to 140 printable ASCII characters), e.g. "Empty state after deleting the last project". Shown under the image in the PR comment. |
|---|
replace | boolean | Overwrite an existing object on a non-gh/ key. Default false. No effect on gh/ keys, which always overwrite. |
|---|
Can overwrite or deletefiles:writeHosted only
Get short-lived upload URLs so a shell can send files straight from disk, without base64 in the tool call. Use this instead of put when the files are on a local or sandbox disk and you can run curl. Takes put's arguments without the bytes, plus files: [{ filename, alt? }] (max 20). This server has no git: in a checkout, pass repo and branch read from git. Run each returned curl line from the folder holding the file (or swap in its path); the response is the same JSON put returns, including markdown. URLs expire after 15 minutes; each takes a file up to its maxBytes (the workspace's upload limit, at most 100 MB). With pr/issue, call comment once after every upload succeeds. If curl gets a 403 from a proxy, the sandbox blocks agents.uploads.sh: ask the person to allow it, or fall back to put with contentBase64. All uploads are public.
Returns workspaceexpiresAtuploadsnexthint
| Parameter | Type | Description |
|---|
filesrequired | object[] | Files to upload, one URL each (max 20). |
|---|
prefix | string | Key prefix for the default key layout (default: screenshots). |
|---|
repo | string | GitHub owner/name. Required with pr/issue/branch. Optional otherwise (default: misc). This server has no git: in a checkout, read it with git remote get-url origin. |
|---|
ref | string | Optional key segment (default: today). Cannot combine with pr/issue/branch. |
|---|
pr | number | Attach to this pull request (stable gh/ key). Mutually exclusive with issue and branch. Requires repo. |
|---|
issue | number | Attach to this issue (stable gh/ key). Mutually exclusive with pr and branch. Requires repo. |
|---|
branch | string | Git branch (git branch --show-current). Stages under it, or targets its open PR when the repo is linked to this workspace and exactly one is open (the result's next says which). Requires repo. Call promote once a PR opens for staged files. |
|---|
alt | string | Alt text for the markdown (default: filename). |
|---|
width | number | Emit <img width=…> markdown instead of a plain image embed. |
|---|
metadata | object | Queryable tags for later search (key→value). Use path for the route (e.g. /settings), not route/page. Omit to leave existing tags; pass an object (even {}) to replace them. state, app, screen and caption have their own fields. On pr/issue/branch, gh.* is set for you. |
|---|
state | "before" | "after" | "empty" | "error" | "loading" | The UI state this image shows. Set it whenever the image is one side of a comparison — before/after is the most useful pair in a PR, and is what makes find_files with state=after work later. |
|---|
app | string | Which surface is shown: web, ios, android, cli. Worth setting only when the same route exists on more than one surface. |
|---|
screen | string | The app screen shown, for views with no route (a mobile or desktop screen), e.g. "Chat". Shown under the image in the PR comment. Use path in metadata for web routes. |
|---|
caption | string | What the shot shows, in plain words (up to 140 printable ASCII characters), e.g. "Empty state after deleting the last project". Shown under the image in the PR comment. |
|---|
replace | boolean | Overwrite an existing object on a non-gh/ key. Default false. No effect on gh/ keys, which always overwrite. |
|---|
promotePromote staged attachments
Can overwrite or deletefiles:writeHosted only
Copy staged or existing files into a PR's stable gh/…/pull/… prefix, then refresh the managed comment. Pass branch and/or keys. Requires repo and pr.
Returns promotionattachedattachFailurescommentcommentErrorhint
| Parameter | Type | Description |
|---|
reporequired | string | GitHub owner/name. Required — this server cannot infer it from git. |
|---|
prrequired | number | Pull request number to promote/attach into. Never applies to issues. |
|---|
branch | string | Staged branch to copy into the PR. |
|---|
keys | string[] | Already-uploaded object keys or uploads.sh URLs to copy into the PR. One bad source does not abort the rest. |
|---|
move | boolean | For keys only: delete each source after a successful copy. Default false. Ignored for the branch sweep. |
|---|
comment | boolean | Refresh the managed attachments comment after a successful copy. Default true. A comment failure never fails the copy. |
|---|
listList files
Read-onlyfiles:read
List uploaded objects in the workspace, optionally filtered by key prefix. Paginate with cursor; each item includes its public URL when the workspace has one.
Returns itemscursorprefixes
| Parameter | Type | Description |
|---|
prefix | string | Key prefix filter. |
|---|
limit | number | Page size (default 100, max 1000). |
|---|
cursor | string | Pagination cursor from a previous call. |
|---|
Writesfiles:write
Clear staged files for a branch, or specific keys, without deleting them. Sets gh.status=unstaged so they drop out of auto-promotion. Pass repo and branch, or keys. Needs files:write.
Returns dryRunrepobranchfilestruncated
| Parameter | Type | Description |
|---|
repo | string | GitHub owner/name. Required — this server cannot infer it from git. |
|---|
branch | string | Branch whose staged files to clear. Requires repo. Do not combine with keys. |
|---|
keys | string[] | Object keys to unstage. Do not combine with branch. |
|---|
dryRun | boolean | Report what would change without writing. |
|---|
Read-onlyfiles:read
Search files by metadata (filters) and/or filename substring (name). At least one is required.
Returns itemscursortruncated
| Parameter | Type | Description |
|---|
filters | object | Equality filters; all must match. Use path for the route (e.g. /settings), not route/page. Optional when name is set. |
|---|
name | string | Case-insensitive substring match on object keys (1–128 chars). Optional when filters is non-empty. |
|---|
prefix | string | Key prefix filter, combinable with filters/name. |
|---|
limit | number | Page size (default 50, max 500). |
|---|
cursor | string | Opaque continuation from a previous call's cursor. Pass it back unchanged with the same filters/name to get the next page; a null cursor means there are no more pages. |
|---|
Read-onlyfiles:read
Read the queryable tags on one file. Returns { metadata } (empty when none).
Returns metadata
| Parameter | Type | Description |
|---|
keyrequired | string | Object key to inspect. |
|---|
Can overwrite or deletefiles:write
Set or delete queryable tags on an existing file. set wins over delete for the same key. Tags appear on the public file page — do not store secrets. Requires set and/or delete.
Returns metadata
| Parameter | Type | Description |
|---|
keyrequired | string | Object key to update. |
|---|
set | object | Keys to set or overwrite. Use path for the route (e.g. /settings), not route/page. |
|---|
delete | string[] | Keys to remove. |
|---|
Read-onlyfiles:read
List metadata keys in the workspace (with counts). Pass key to list that key's values instead. Use before find_files.
Returns keystruncatedkeyvalues
| Parameter | Type | Description |
|---|
key | string | When set, return distinct values for this metadata key (with counts) instead of the key list. |
|---|
Can overwrite or deletefiles:delete
Permanently delete one uploaded file by key, along with its metadata. A files:write token can delete a gh/ object the server stamped as its upload. Older files and any other object need files:delete. Deleting a PR or issue attachment refreshes the managed comment.
Returns keydeleteddryRuncommentRefreshedcommentHint
| Parameter | Type | Description |
|---|
keyrequired | string | Object key to delete. |
|---|
Read-onlyfiles:read
List uploads held for review. The classifier holds a file it thinks shows a secret (an API key, a password, a token) or sensitive personal data (an ID, a card number). A held file stays out of the managed PR comment, feeds, and galleries until a workspace member approves it with approve. A signed-in member sees the real file on its /f/ page. On hosted storage an image URL returns a Held for review card, and any other raw URL returns 404. Pass pr/issue + repo for one PR or issue, or prefix. Each item has reason (secret: api_key, pii: financial), area (an approximate box around the flagged content as fractions of the image, null when unknown), and sha (the content hash, null when unknown). approve with pr or issue sends that hash.
Returns items
| Parameter | Type | Description |
|---|
pr | number | Held files on this pull request. |
|---|
issue | number | Held files on this issue. |
|---|
repo | string | GitHub owner/name. Required — this server cannot infer it from git. |
|---|
prefix | string | Only keys under this prefix. |
|---|
approveApprove held files
Writesfiles:write
Release uploads held for review (see list_held): pass keys, or pr/issue + repo to approve every held file there. The file returns at the same URL and the managed PR comment re-syncs. Check the file first: if it shows a real credential, rotate it and delete the file instead of approving. Same as uploads approve.
Returns files
| Parameter | Type | Description |
|---|
keys | string[] | Held keys to approve. |
|---|
pr | number | Approve every held file on this pull request. |
|---|
issue | number | Approve every held file on this issue. |
|---|
repo | string | GitHub owner/name. Required — this server cannot infer it from git. |
|---|
Read-onlyfiles:readHosted only
Recent GitHub-tagged activity in this workspace, grouped by pull request (default) or by repo. Pull rows are pull requests that received media tagged gh.kind=pull, newest last_media_at first. The default window is 90 days. Set all to true to lift it. Optional repo and state (open, closed, or merged) narrow those rows. A title is included only when the repo is linked to this workspace. Repo rows are distinct gh.repo values, newest metadata updated_at first. These times are not the object's uploaded-at. Untagged uploads are absent. This does not publish a feed. Pass cursor back unchanged with the same arguments for the next page. Use list_repo_files to open one repo's files, and find_files for tag or filename search in key order.
Returns byrepospullscursor
| Parameter | Type | Description |
|---|
by | "pull" | "repo" | Group the page by pull request ("pull", the default) or by repository ("repo"). |
|---|
repo | string | When by is pull, keep rows for this owner/repo only. Ignored values are rejected when by is repo. |
|---|
state | "open" | "closed" | "merged" | When by is pull, keep rows in this state. Rows with no stored state drop out. Rejected when by is repo. |
|---|
all | boolean | When by is pull, include pull requests whose last media is older than 90 days. Default false. Rejected when by is repo. |
|---|
limit | number | Page size. Pulls default to 20 (max 100). Repos default to 20 (max 50). |
|---|
cursor | string | Opaque cursor from the previous page. Send it back with the same by, repo, state, and all. |
|---|
Read-onlyfiles:readHosted only
Files tagged with gh.repo for one repository, newest metadata updated_at first. That time is not the object's uploaded-at. repo is owner/name. Optional pr matches gh.number. Optional path matches the path tag exactly. type is a filename suffix class: screenshot, video, or other. PDFs are other. Promoted copies (gh.status=promoted) are omitted. This does not publish a feed. Pass cursor back unchanged with the same arguments for the next page.
Returns itemscursor
| Parameter | Type | Description |
|---|
reporequired | string | GitHub repository as owner/name. Matching is case-insensitive. |
|---|
pr | number | When set, keep files tagged with this pull-request number (gh.number). |
|---|
path | string | When set, keep files whose path tag equals this string. |
|---|
type | "screenshot" | "video" | "other" | Filename suffix class. screenshot is png/jpg/jpeg/webp/gif/avif, video is mp4/webm/mov, and other is everything else (including PDF). |
|---|
limit | number | Page size (default 50, max 100). |
|---|
cursor | string | Opaque cursor from the previous page. Send it back with the same repo, pr, path, and type. |
|---|
Read-onlyfiles:readHosted only
Whether files staged for a repo will auto-attach into that repo's PRs from this workspace. Returns a tri-state binding: "self" (this repo is bound to this workspace — staged files will auto-attach), "other" (bound to a different workspace — they will not; the owning workspace is deliberately never disclosed), or "none" (unbound).
Returns binding
| Parameter | Type | Description |
|---|
reporequired | string | GitHub repo as owner/name. |
|---|
Writesfiles:write
Create a public ordered media gallery in this workspace. The returned canonical URL is suitable for an agent response, but anyone who knows it can view the gallery and its media.
Returns idurlworkspacetitledescriptionvisibilitycoverItemIdversioncreatedAtupdatedAtitemsitemCountreferences
| Parameter | Type | Description |
|---|
titlerequired | string | Gallery title (1–120 characters). |
|---|
description | string | Optional public gallery description. |
|---|
Read-onlyfiles:read
Get a workspace-owned gallery, including its ordered media and canonical public URL. Gallery media is public to anyone with the URL.
Returns idurlworkspacetitledescriptionvisibilitycoverItemIdversioncreatedAtupdatedAtitemsitemCountreferences
| Parameter | Type | Description |
|---|
galleryIdrequired | string | Opaque gallery ID. |
|---|
Writesfiles:write
Add one existing, publicly served workspace object to a gallery. The tool reads the current version before writing and does not upload or delete the object.
Returns idobjectKeyfilenamepositioncaptionaltTextcreatedAtstatusurlembedUrlpageUrlcontentTypesizeuploadedmodifiedposterUrlvideoDimensions
| Parameter | Type | Description |
|---|
galleryIdrequired | string | Opaque gallery ID. |
|---|
objectKeyrequired | string | Existing public object key to add. |
|---|
caption | string | Optional public caption. |
|---|
altText | string | Optional public alt text. |
|---|
Writesfiles:write
Link a gallery to an external reference. Uses provider-neutral fields; github currently accepts owner/repo#number or a strict GitHub issue/PR URL. No GitHub credentials or API calls are used.
Returns idproviderresourceTypecoordinatecanonicalUrlcreatedAttitlekind
| Parameter | Type | Description |
|---|
galleryIdrequired | string | Opaque gallery ID. |
|---|
providerrequired | string | External provider (currently github). |
|---|
coordinaterequired | string | Provider-native external reference coordinate. |
|---|
Read-onlyfiles:read
Find galleries in this workspace linked to an external reference. Returns canonical public gallery URLs without contacting the provider.
Returns galleriesnextCursor
| Parameter | Type | Description |
|---|
providerrequired | string | External provider (currently github). |
|---|
coordinaterequired | string | Provider-native external reference coordinate. |
|---|
limit | number | Page size (default 50, max 100). |
|---|
Writesfiles:write
Create a public newest-first screenshot feed (same product as CLI uploads feed create). Pass repo alone for the whole GitHub repo. Pass pr plus repo — or github as owner/repo#123 / a GitHub PR URL — to scope that same feed to one pull request. issue does the same for an issue. Optional path filters by page-path metadata. Creating the same scope again returns the existing URL. This is a live query, not a curated gallery. Anyone who knows the URL can view it. See https://uploads.sh/docs/feeds.
Returns idurlworkspacerepopathnumberkindtitlecreatedAtupdatedAtitems
| Parameter | Type | Description |
|---|
repo | string | GitHub owner/repo, for example acme/app. Required unless github is set. |
|---|
pr | integer | Scope the feed to this pull request. Same product as a repo feed — one extra filter. Mutually exclusive with issue and github. |
|---|
issue | integer | Scope the feed to this issue. Mutually exclusive with pr and github. |
|---|
github | string | Scope via owner/repo#number or a GitHub issue/PR URL. Supplies repo when omitted. Mutually exclusive with pr and issue. |
|---|
path | string | Optional exact page-path metadata filter, for example /settings. |
|---|
Read-onlyfiles:read
Get a workspace-owned change feed by ID, including its current newest-first screenshots and the canonical public /c/<id> URL. Each item includes pageUrl (/c/<id>/<item>) for the pager. The feed may be repo-wide or scoped to one pull request / issue (see number and kind on the result). Anyone with the URL can view the media.
Returns idurlworkspacerepopathnumberkindtitlecreatedAtupdatedAtitems
| Parameter | Type | Description |
|---|
feedIdrequired | string | Opaque feed ID. |
|---|
Read-onlyAny token
Show the current uploads.sh identity: the workspace this call acts in, every workspace this connection can use (workspaces; pass one as workspace on any tool), and its scopes. A successful result also means the server is up.
Returns okworkspaceworkspacesscopesuserIdserviceTokensignedInapiUrl
Read-onlyfiles:read
Workspace storage and monthly upload counters (and remaining headroom when budgets are configured).
Returns workspacebytesobjectssharedBytessharedObjectsuploadsInPeriodperiodStartupdatedAtstorageBudgetBasismaxStorageBytesstorageRemainingBytesmaxUploadsPerPerioduploadsRemainingscopesplanstorage
Writesfiles:write
Rebuild usage ledger bytes/objects from storage (source of truth). Preserves the monthly upload counter. Requires files:write.
Returns workspacebytesobjectspreviouschangedusageunprefixedBucket
Can overwrite or deletefiles:delete
Delete objects older than the workspace retentionDays setting, then reconcile. Skips if retention is unset. Requires files:delete.
Returns skippedreasonworkspaceretentionDayscutoffdeletedfreedByteskeyskeysTruncatedreconcile
Read-onlyAny token
Search the public uploads.sh documentation. Use this to answer questions about uploads.sh product workflows, including: attaching screenshots and video to GitHub PRs and issues; staging files before a PR exists; galleries; the GitHub App; comment config (.uploads.yml); hosted MCP and agent setup; screenshot capture and annotate; plans and limits; bring-your-own bucket. Same as uploads docs. Returns titles, URLs, and snippets. Pass page to fetch the full markdown of one page (slug, path, or URL). Omit query to list the catalog.
Returns urlqueryresultstotal
| Parameter | Type | Description |
|---|
query | string | Search query (e.g. 'stage before a PR'). A single slug like 'attach' fetches that page. |
|---|
page | string | Fetch one page as markdown. Accepts a slug (attach), path (/docs/agents), or https://uploads.sh URL. |
|---|
limit | number | How many search hits to return (default 5, max 50). Ignored when fetching one page. |
|---|
Read-onlyAny token
Read recent uploads.sh product updates (platform and CLI). Returns the latest entries with titles, dates, summaries, and a link to the full changelog at https://uploads.sh/changelog. Same as uploads changelog.
Returns urlfeedentries
| Parameter | Type | Description |
|---|
limit | number | How many entries to return (default 5, max 50). |
|---|
Read-onlyfiles:readHosted only
Read staged media for one explicit repository and branch in the connected workspace. Read the current checkout's Git remote and branch before calling; the hosted server cannot infer them. Repository and branch match stored lowercase metadata. Excludes promoted and unstaged files. Private, held, missing, and unsupported previews are placeholders. Pass cursor unchanged with the same scope to load more; a non-null cursor means more pages even if this page is empty. Results use object-key order, not newest-first.
Returns repobranchcursoritems
| Parameter | Type | Description |
|---|
reporequired | string | Explicit GitHub repository owner/name. |
|---|
branchrequired | string | Explicit Git branch, for example feature/settings. |
|---|
cursor | string | |
|---|
limit | integer | |
|---|
Read-onlyfiles:readHosted only
Resolve the pull request for one explicit repository and branch. Pass the current PR number when known. Otherwise look up one open same-repository PR only when the repository is linked to this workspace. An unavailable resolution requires an explicit PR number; it does not mean that the PR has no attached files.
Returns repobranchprprResolution
| Parameter | Type | Description |
|---|
reporequired | string | |
|---|
branchrequired | string | |
|---|
pr | integer | |
|---|
Read-onlyfiles:readHosted only
Read media attached to one explicit repository and PR in the connected workspace. Pass the displayed branch as context. PR membership uses repository and PR number, including direct attachments without branch tags. Private and held files remain placeholders. Continue with the returned cursor and the same repository and PR; never combine PRs.
Returns repobranchcursoritemspr
| Parameter | Type | Description |
|---|
reporequired | string | |
|---|
branchrequired | string | |
|---|
prrequired | integer | |
|---|
cursor | string | |
|---|
limit | integer | |
|---|
Read-onlyfiles:readHosted only
List distinct repository/branch pairs with staged files in the connected workspace. Use an explicit pair with list_staged_media; never combine different branches. Results use repository/branch order. Pass cursor unchanged for the next page.
Returns cursorscopes
| Parameter | Type | Description |
|---|
cursor | string | |
|---|
limit | integer | |
|---|
Read-onlyfiles:readHosted only
Open Uploads beside the conversation to review staged files and files attached to the current PR. Read the checkout's Git remote and branch and pass repo (owner/name), branch, and the current pr number when known. Without repo and branch, show a scope picker; never assume a checkout. Refresh keeps the displayed scope until it is changed.
| Parameter | Type | Description |
|---|
repo | string | Explicit repository as owner/name. |
|---|
branch | string | Explicit Git branch for this tray. |
|---|
pr | integer | Current pull-request number, when known. |
|---|