From f7be88e9243273d00beaa82089e691685a5750df Mon Sep 17 00:00:00 2001 From: Jeremy Daer Date: Thu, 6 Aug 2026 00:35:27 -0700 Subject: [PATCH] Sync API docs from bc3 --- sections/uploads.md | 82 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 80 insertions(+), 2 deletions(-) diff --git a/sections/uploads.md b/sections/uploads.md index 1da1f30..f9878db 100644 --- a/sections/uploads.md +++ b/sections/uploads.md @@ -6,6 +6,7 @@ Endpoints: - [Get uploads](#get-uploads) - [Get an upload](#get-an-upload) - [Get upload versions](#get-upload-versions) +- [Create an upload version](#create-an-upload-version) - [Create an upload](#create-an-upload) - [Update an upload](#update-an-upload) - [Trash an upload][trash] @@ -184,7 +185,18 @@ curl -s -H "Authorization: Bearer $ACCESS_TOKEN" https://3.basecampapi.com/$ACCO Get upload versions ------------------- -* `GET /uploads/2/versions.json` will return a list of version events for the upload with an ID of `2`, in reverse chronological order. Each version event represents a file replacement. +* `GET /uploads/2/versions.json` will return a list of version events for the upload with an ID of `2`, in reverse chronological order. + +Three `action`s appear here: `created` and `active` mark the upload's publication, and `blob_changed` marks a file replacement. Filter on `action == "blob_changed"` to list only the replacements. + +Each version event carries an `upload` object describing the file that version recorded: + +* `filename`, `content_type` and `byte_size` — the file as it was at that version. +* `download_url` — downloads that specific version's file, unlike the upload's own `download_url`, which always serves the latest one. +* `app_download_url` — the equivalent link for the Basecamp web app. +* `current` — `true` for the most recent version, `false` for the rest. Exactly one version is current. Note that this is the newest *version*, which isn't necessarily the file you get from the upload's own `download_url`: [updating an upload](#update-an-upload) changes its metadata without recording a new version. + +The whole `upload` object is omitted — not `null` — on the rare version whose file has since been removed from the account. The version event itself is still listed, so treat `upload` as optional when decoding. ###### Example JSON Response @@ -223,6 +235,14 @@ Get upload versions "can_manage_people": true, "can_access_timesheet": true, "can_access_hill_charts": true + }, + "upload": { + "content_type": "image/png", + "byte_size": 1281, + "filename": "company-logo.png", + "download_url": "https://3.basecampapi.com/195539477/buckets/2085958505/uploads/1069480281/versions/1052473756/download/company-logo.png", + "app_download_url": "https://storage.3.basecamp.com/195539477/buckets/2085958505/uploads/1069480281/versions/1052473756/download/company-logo.png", + "current": true } } ] @@ -234,6 +254,51 @@ Get upload versions curl -s -H "Authorization: Bearer $ACCESS_TOKEN" https://3.basecampapi.com/$ACCOUNT_ID/uploads/2/versions.json ``` +Create an upload version +------------------------ + +* `POST /uploads/2/versions.json` replaces the file of the upload with an ID of `2`. + +The upload keeps its ID, its URL and its comments, and the previous file stays available as a past version. Use this instead of [creating a new upload](#create-an-upload) when you're publishing a new release of the same file and want its link to keep working. + +**Required parameters**: `attachable_sgid` for an uploaded attachment. See the [Create an attachment][attachments] endpoint for more info on uploading attachments. + +_Optional parameters_: +* `base_name` - a new file name for the upload. `base_name` should be a file name *without* an extension (e.g. `"pizza"` for `"pizza.png"`). Omit it to keep the name of the file you uploaded. +* `description` - containing information about the upload. See our [Rich text guide][rich] for what HTML tags are allowed. Omit it to carry the previous version's description forward, or send `""` or `null` to clear it. +* `notify` - who to notify about the replacement: `default` (people subscribed to project notifications), `everyone`, or `custom` (specific people via `subscriptions`). Omit both `notify` and `subscriptions` to notify nobody. +* `subscriptions` - an array of people IDs to notify about the replacement and subscribe to the upload. Used when `notify` is `custom`, which is also how a `subscriptions` array sent without `notify` is read. + +Notified people are subscribed to the upload. Client visibility isn't a parameter here: a replacement never changes who can see the upload, so clients are in the audience only when the upload is already visible to them. + +This endpoint will return `201 Created` with the current JSON representation of the upload if the replacement was a success. See the [Get an upload](#get-an-upload) endpoint for more info on the payload. + +A replacement stores the new file alongside every past version, so it counts against the account's storage. If the account has reached its storage limit you'll see a `507 Insufficient Storage` and a response of: + +```json +{ + "error": "The storage limit for this account has been reached." +} +``` + +###### Example JSON Request + +```json +{ + "attachable_sgid": "BAh2CEkiCGdpZAY6BkVUSSIsZ2lkOi7vYmMzL0F0dGFjaG1lbnQvNzM4NDcyNj9leHBpcmVzX2luBjsAVEkiDHB1cnBvc2UGOwBUSSIPYXR0YWNoYWJsZQY7AFRJIg9leHBpcmVzX2F0BjsAVDA=--13982201abe18044c897e32979c7dccfe8add9c1", + "description": "
Yum
", + "base_name": "yummy_pizza" +} +``` + +###### Copy as cURL + +```shell +curl -s -H "Authorization: Bearer $ACCESS_TOKEN" -H "Content-Type: application/json" \ + -d '{"attachable_sgid":"BAh…9c1","description":"
Yum
","base_name":"yummy_pizza"}' \ + https://3.basecampapi.com/$ACCOUNT_ID/uploads/2/versions.json +``` + Create an upload ---------------- @@ -246,7 +311,13 @@ _Optional parameters_: * `base_name` - a new file name for the upload. `base_name` should be a file name *without* an extension (e.g. `"pizza"` for `"pizza.png"`). * `visible_to_clients` - top-level boolean. When the project has clients enabled, whether the upload is visible to them. Defaults to `false` (team callers creating directly under the docked tool); a **client** caller always creates client-visible records. Applies only when creating directly in the tool's vault; items created inside a folder inherit the folder's visibility. See [Client visibility][client_visibility] to change it after creation. -This endpoint will return `201 Created` with the current JSON representation of the upload if the creation was a success. See the [Get an upload](#get-an-upload) endpoint for more info on the payload. +This endpoint will return `201 Created` with the current JSON representation of the upload if the creation was a success. See the [Get an upload](#get-an-upload) endpoint for more info on the payload. If the account has reached its storage limit you'll see a `507 Insufficient Storage` and a response of: + +```json +{ + "error": "The storage limit for this account has been reached." +} +``` ###### Example JSON Request @@ -271,6 +342,12 @@ Update an upload * `PUT /uploads/2.json` allows changing the `description` and `base_name` of the upload with an ID of `2`. +This changes the upload's metadata only. To replace the file itself, see [Create an upload version](#create-an-upload-version). + +_Optional parameters_: +* `base_name` - a new file name for the upload. `base_name` should be a file name *without* an extension (e.g. `"pizza"` for `"pizza.png"`). Omitting it — or sending `""` — keeps the current name. +* `description` - containing information about the upload. See our [Rich text guide][rich] for what HTML tags are allowed. Omit it to leave the description alone, or send `""` or `null` to clear it. + This endpoint will return `200 OK` with the current JSON representation of the upload if the update was a success. See the [Get an upload](#get-an-upload) endpoint for more info on the payload. ###### Example JSON Request @@ -298,6 +375,7 @@ The following project-scoped routes are still supported and will remain availabl * `GET /buckets/1/vaults/2/uploads.json` → [Get uploads](#get-uploads) * `GET /buckets/1/uploads/2.json` → [Get an upload](#get-an-upload) * `GET /buckets/1/uploads/2/versions.json` → [Get upload versions](#get-upload-versions) +* `POST /buckets/1/uploads/2/versions.json` → [Create an upload version](#create-an-upload-version) * `POST /buckets/1/vaults/2/uploads.json` → [Create an upload](#create-an-upload) * `PUT /buckets/1/uploads/2.json` → [Update an upload](#update-an-upload)