From d0a7a86f56987473b5fccc7a53249db0b7d22eeb Mon Sep 17 00:00:00 2001 From: jeissonneira Date: Sat, 2 May 2026 10:24:40 -0500 Subject: [PATCH 1/2] Add API documentation for External links --- README.md | 1 + sections/external_links.md | 136 +++++++++++++++++++++++++++++++++++++ 2 files changed, 137 insertions(+) create mode 100644 sections/external_links.md diff --git a/README.md b/README.md index 544fb4a..1c9d54b 100644 --- a/README.md +++ b/README.md @@ -302,6 +302,7 @@ API endpoints - [Documents](sections/documents.md#documents) - [Events](sections/events.md#events) - [Everything](sections/everything.md#everything) +- [External links](sections/external_links.md#external-links) - [Forwards](sections/forwards.md#forwards) - [Gauges](sections/gauges.md#gauges) - [Google documents](sections/google_documents.md#google-documents) diff --git a/sections/external_links.md b/sections/external_links.md new file mode 100644 index 0000000..980786c --- /dev/null +++ b/sections/external_links.md @@ -0,0 +1,136 @@ +External links +============== + +External links (previously known as **doors**) are quick links to outside services like Dropbox, Google Drive, Trello, or any arbitrary URL that appear in a project's "External links" section. Each external link has a service type, URL, title, and optional description. + +External links are a separate collection from tools and do not appear in the project's `dock` array. The endpoint URLs continue to use the original `doors` resource name. + +Endpoints: + +- [Get an external link](#get-an-external-link) +- [Create an external link](#create-an-external-link) +- [Update an external link](#update-an-external-link) +- [Trash an external link](#trash-an-external-link) + + +Get an external link +-------------------- + +* `GET /buckets/1/dock/doors/2.json` for the external link with ID `2` in the project with ID `1`. + +This endpoint behaves as a redirector rather than returning a JSON resource: it responds with `302 Found` and a `Location` header pointing to the external link's `url`. There is currently no public endpoint that returns the JSON representation of a single external link. + +To retrieve external link metadata (id, title, url, service, status), use [Search](search.md#search) and filter results by `type: "Door"`. The shape returned in search results is shown below. + +###### Example JSON Response + +```json +{ + "id": 1069479500, + "status": "active", + "visible_to_clients": false, + "created_at": "2026-02-12T06:09:34.667Z", + "updated_at": "2026-02-12T06:13:57.731Z", + "title": "Design system", + "inherits_status": true, + "type": "Door", + "url": "https://www.figma.com/file/abc", + "app_url": "https://3.basecampapi.com/195539477/buckets/2085958504/dock/doors/1069479500", + "bookmark_url": "https://3.basecampapi.com/195539477/my/bookmarks/BAh7BkkiC19yYWlscwY6BkVUewdJIglkYXRhBjsAVEkiLmdpZDovL2JjMy9SZWNvcmRpbmcvMTA2OTQ3OTUwMD9leHBpcmVzX2luBjsAVEkiCHB1cgY7AFRJIg1yZWFkYWJsZQY7AFQ=--placeholder.json", + "subscription_url": "https://3.basecampapi.com/195539477/buckets/2085958504/recordings/1069479500/subscription.json", + "position": 1, + "bucket": { + "id": 2085958504, + "name": "The Leto Laptop", + "type": "Project" + }, + "creator": { + "id": 1049715913, + "name": "Victor Cooper", + "email_address": "victor@honchodesign.com" + }, + "service": { + "name": "Figma", + "example_url": "https://www.figma.com/file/...", + "code": "figma", + "valid_patterns": ["www\\.figma\\.com\\/file\\/.+"], + "supporting_text": null + }, + "description": null, + "content": null +} +``` + + +###### Copy as cURL + +```shell +curl -s -H "Authorization: Bearer $ACCESS_TOKEN" \ + -A "MyApp (yourname@example.com)" \ + https://3.basecampapi.com/$ACCOUNT_ID/buckets/1/dock/doors/2.json +``` + + +Create an external link +----------------------- + +* `POST /buckets/1/dock/doors.json` creates a new external link in the project with ID `1`. + +**Required parameters**: +* `door[service]` - the service type. Use `other` for a generic external link, or one of `dropbox`, `google_drive`, `trello`, `github`, `figma`, `airtable`, `notion`, `slack`, `zoom`. Unrecognized values return `422 Unprocessable Entity`. +* `door[url]` - the URL the link points to. +* `door[title]` - the title shown in the External links section. + +_Optional parameters_: +* `door[description]` - a short description shown beneath the title. +* `door[image]` - a thumbnail image (binary, multipart upload). + +Unlike most BC3 endpoints, this endpoint expects parameters in `application/x-www-form-urlencoded` form (with bracketed keys), not JSON. It returns `302 Found` redirecting to the project's dock edit page on success with an empty response body. The new external link's ID is not returned — discover it via [Search](search.md#search). + +###### Copy as cURL + +```shell +curl -s -H "Authorization: Bearer $ACCESS_TOKEN" \ + -A "MyApp (yourname@example.com)" \ + --data-urlencode "door[service]=other" \ + --data-urlencode "door[url]=https://example.com" \ + --data-urlencode "door[title]=External link" \ + --data-urlencode "door[description]=Optional description" \ + https://3.basecampapi.com/$ACCOUNT_ID/buckets/1/dock/doors.json +``` + + +Update an external link +----------------------- + +* `PUT /buckets/1/dock/doors/2.json` updates the external link with ID `2` in the project with ID `1`. + +Any of the [Create an external link](#create-an-external-link) parameters may be supplied. Like create, this endpoint expects `application/x-www-form-urlencoded` parameters with bracketed keys and returns `302 Found` redirecting to the project's dock edit page on success with an empty response body. + +###### Copy as cURL + +```shell +curl -s -H "Authorization: Bearer $ACCESS_TOKEN" \ + -A "MyApp (yourname@example.com)" \ + -X PUT \ + --data-urlencode "door[title]=Updated title" \ + --data-urlencode "door[url]=https://example.com/new-path" \ + https://3.basecampapi.com/$ACCOUNT_ID/buckets/1/dock/doors/2.json +``` + + +Trash an external link +---------------------- + +* `DELETE /buckets/1/dock/doors/2.json` trashes the external link with ID `2` in the project with ID `1`. + +This endpoint will return `204 No Content` if successful. Trashed external links are soft-deleted: their `status` becomes `"deleted"` (visible in [Search](search.md#search) results) and they no longer appear in the project's External links section. + +###### Copy as cURL + +```shell +curl -s -H "Authorization: Bearer $ACCESS_TOKEN" \ + -A "MyApp (yourname@example.com)" \ + -X DELETE \ + https://3.basecampapi.com/$ACCOUNT_ID/buckets/1/dock/doors/2.json +``` From 768ec10442a52f15f170d32c4578d201f843a8d3 Mon Sep 17 00:00:00 2001 From: Jeremy Daer Date: Wed, 22 Jul 2026 10:13:05 -0700 Subject: [PATCH 2/2] Correct External links docs and add the list endpoint Reconciles the draft against current source: external links are dock tools with a real JSON get/rename/trash surface via /dock/tools/:id.json; the door-route PUT mutates then 406s (so it isn't advertised); create accepts JSON or form encoding and returns a 302 with no id; the service catalogue is large with an `other` fallback and doors don't enforce per-service URL patterns. Documents the list endpoint (GET /projects/recordings.json?type=Door) and aligns styling with cloud_files.md / tools.md. --- sections/external_links.md | 262 +++++++++++++++++++++++++------------ sections/recordings.md | 2 +- 2 files changed, 179 insertions(+), 85 deletions(-) diff --git a/sections/external_links.md b/sections/external_links.md index 980786c..ee24d25 100644 --- a/sections/external_links.md +++ b/sections/external_links.md @@ -1,136 +1,230 @@ External links ============== -External links (previously known as **doors**) are quick links to outside services like Dropbox, Google Drive, Trello, or any arbitrary URL that appear in a project's "External links" section. Each external link has a service type, URL, title, and optional description. - -External links are a separate collection from tools and do not appear in the project's `dock` array. The endpoint URLs continue to use the original `doors` resource name. +An external link (historically a **door**) is a [dock tool][tools] that points to an +outside service — a Figma file, a Dropbox folder, a GitHub repository, or any arbitrary +URL. External links show up in a project's "External links" section rather than inside a +[vault][vaults], which makes them the legacy, dock-based sibling of the modern vault-based +[cloud files][cloud_files] and [Google documents][google_documents]. The endpoint URLs +keep the original `doors` resource name. + +Because external links are dock tools, they share the generic dock-tool operations +documented in [Tools][tools]: getting, renaming, and trashing a single external link all +go through `/dock/tools/:id.json`. This section covers those cross-links plus the +door-specific parts: the list endpoint and its full shape, the bespoke create path, and +the legacy redirector. + +External links are deliberately **omitted from a project's `dock` array**, so the +"discover tools via the dock" advice in [Tools][tools] does not surface them. Use the +list endpoint below to find a project's external links. Endpoints: -- [Get an external link](#get-an-external-link) +- [List external links](#list-external-links) +- [Get a single external link](#get-a-single-external-link) - [Create an external link](#create-an-external-link) -- [Update an external link](#update-an-external-link) +- [Rename an external link](#rename-an-external-link) +- [Change a URL, service, or description](#change-a-url-service-or-description) - [Trash an external link](#trash-an-external-link) +[tools]: tools.md +[cloud_files]: cloud_files.md +[google_documents]: google_documents.md +[recordings]: recordings.md +[vaults]: vaults.md -Get an external link --------------------- - -* `GET /buckets/1/dock/doors/2.json` for the external link with ID `2` in the project with ID `1`. +List external links +------------------- -This endpoint behaves as a redirector rather than returning a JSON resource: it responds with `302 Found` and a `Location` header pointing to the external link's `url`. There is currently no public endpoint that returns the JSON representation of a single external link. +* `GET /projects/recordings.json?type=Door` will return a [paginated list][pagination] of + external links across the active [projects][projects] visible to the current user. + Pass `bucket` to scope to specific projects (which also includes archived ones). -To retrieve external link metadata (id, title, url, service, status), use [Search](search.md#search) and filter results by `type: "Door"`. The shape returned in search results is shown below. +This is the canonical way to enumerate external links and the only endpoint that returns +their **full shape**: the external `url`, the `service` struct, and the `description`. It +extends the generic [Get recordings][get_recordings] endpoint, so it accepts the same +`bucket`, `status`, `sort`, and `direction` query parameters. ###### Example JSON Response - + ```json -{ - "id": 1069479500, - "status": "active", - "visible_to_clients": false, - "created_at": "2026-02-12T06:09:34.667Z", - "updated_at": "2026-02-12T06:13:57.731Z", - "title": "Design system", - "inherits_status": true, - "type": "Door", - "url": "https://www.figma.com/file/abc", - "app_url": "https://3.basecampapi.com/195539477/buckets/2085958504/dock/doors/1069479500", - "bookmark_url": "https://3.basecampapi.com/195539477/my/bookmarks/BAh7BkkiC19yYWlscwY6BkVUewdJIglkYXRhBjsAVEkiLmdpZDovL2JjMy9SZWNvcmRpbmcvMTA2OTQ3OTUwMD9leHBpcmVzX2luBjsAVEkiCHB1cgY7AFRJIg1yZWFkYWJsZQY7AFQ=--placeholder.json", - "subscription_url": "https://3.basecampapi.com/195539477/buckets/2085958504/recordings/1069479500/subscription.json", - "position": 1, - "bucket": { - "id": 2085958504, - "name": "The Leto Laptop", - "type": "Project" - }, - "creator": { - "id": 1049715913, - "name": "Victor Cooper", - "email_address": "victor@honchodesign.com" - }, - "service": { - "name": "Figma", - "example_url": "https://www.figma.com/file/...", - "code": "figma", - "valid_patterns": ["www\\.figma\\.com\\/file\\/.+"], - "supporting_text": null - }, - "description": null, - "content": null -} +[ + { + "id": 1069480290, + "status": "active", + "visible_to_clients": false, + "created_at": "2026-07-22T15:51:54.872Z", + "updated_at": "2026-07-22T15:51:54.886Z", + "title": "Design system", + "inherits_status": true, + "type": "Door", + "url": "https://www.figma.com/file/abc123/Design-system", + "app_url": "https://3.basecampapi.com/195539477/buckets/2085958504/dock/doors/1069480290", + "bookmark_url": "https://3.basecampapi.com/195539477/my/bookmarks/BAh7BkkiC19yYWlscwY6BkVUewdJIglkYXRhBjsAVEkiLmdpZDovL2JjMy9SZWNvcmRpbmcvMTA2OTQ4MDI5MD9leHBpcmVzX2luBjsAVEkiCHB1cgY7AFRJIg1yZWFkYWJsZQY7AFQ=--01c7c586d5f3a3e368c70860a5055ff3ca520d55.json", + "subscription_url": "https://3.basecampapi.com/195539477/buckets/2085958504/recordings/1069480290/subscription.json", + "position": 8, + "bucket": { + "id": 2085958504, + "name": "The Leto Laptop", + "type": "Project" + }, + "creator": { + "id": 1049715913, + "attachable_sgid": "BAh7BkkiC19yYWlscwY6BkVUewdJIglkYXRhBjsAVEkiK2dpZDovL2JjMy9QZXJzb24vMTA0OTcxNTkxMz9leHBpcmVzX2luBjsAVEkiCHB1cgY7AFRJIg9hdHRhY2hhYmxlBjsAVA==--e627c45e6b34e08862da23906862412620e4d5d9", + "name": "Victor Cooper", + "personable_type": "User", + "title": "Chief Strategist", + "tagline": "Don't let your dreams be dreams", + "location": "Chicago, IL", + "created_at": "2026-07-22T15:48:06.186Z", + "updated_at": "2026-07-22T15:48:07.012Z", + "email_address": "victor@honchodesign.com", + "bio": "Don't let your dreams be dreams", + "admin": true, + "owner": true, + "client": false, + "employee": true, + "time_zone": "America/Chicago", + "avatar_url": "https://3.basecampapi.com/195539477/people/BAhpBMlkkT4=--5fe7b70fbee7a7f0e2e1e19df7579e5d880c753d/avatar", + "company": { + "id": 1033447817, + "name": "Honcho Design" + }, + "can_ping": true, + "can_manage_projects": true, + "can_manage_people": true, + "can_access_timesheet": true, + "can_access_hill_charts": true + }, + "service": { + "name": "Figma", + "example_url": "https://www.figma.com/file/aGVsbG8gZmlnbWEgZmlsZQ", + "code": "figma", + "valid_patterns": [ + "(.*?\\.)?figma\\.com(\\/.*)?" + ], + "supporting_text": "a file or project on Figma" + }, + "description": "
Shared Figma workspace
" + } +] ``` - + ###### Copy as cURL ```shell curl -s -H "Authorization: Bearer $ACCESS_TOKEN" \ - -A "MyApp (yourname@example.com)" \ - https://3.basecampapi.com/$ACCOUNT_ID/buckets/1/dock/doors/2.json + "https://3.basecampapi.com/$ACCOUNT_ID/projects/recordings.json?type=Door" ``` +Get a single external link +-------------------------- + +Because an external link is a dock tool, fetch one with [Get a tool][get_a_tool]: +`GET /dock/tools/:id.json` returns the recording envelope for the external link. + +Note that this envelope's `url` is the external link's Basecamp **redirector** URL — not +the outside address it points to — and it **omits** the `service` and `description` +fields. When you need the external target, the service struct, or the description, use +[List external links](#list-external-links) instead. + +The legacy bucket-scoped route is a redirector rather than a JSON resource: + +* `GET /buckets/1/dock/doors/2.json` responds with `302 Found` and a `Location` header + pointing at the external link's outside `url`. Create an external link ----------------------- -* `POST /buckets/1/dock/doors.json` creates a new external link in the project with ID `1`. - -**Required parameters**: -* `door[service]` - the service type. Use `other` for a generic external link, or one of `dropbox`, `google_drive`, `trello`, `github`, `figma`, `airtable`, `notion`, `slack`, `zoom`. Unrecognized values return `422 Unprocessable Entity`. -* `door[url]` - the URL the link points to. -* `door[title]` - the title shown in the External links section. +* `POST /buckets/1/dock/doors.json` creates a new external link in the [project][projects] + with ID `1`. -_Optional parameters_: -* `door[description]` - a short description shown beneath the title. -* `door[image]` - a thumbnail image (binary, multipart upload). +The create endpoint accepts a JSON body (or `application/x-www-form-urlencoded` form with +bracketed `door[...]` keys) for the ordinary fields, wrapped under a `door` key. Use +`multipart/form-data` when uploading a `door[image]` thumbnail. -Unlike most BC3 endpoints, this endpoint expects parameters in `application/x-www-form-urlencoded` form (with bracketed keys), not JSON. It returns `302 Found` redirecting to the project's dock edit page on success with an empty response body. The new external link's ID is not returned — discover it via [Search](search.md#search). +###### Required parameters -###### Copy as cURL +| Param | Type | Description | +| --------- | ------ | ----------- | +| `service` | String | A short identifier for the external service — e.g. `figma`, `dropbox`, `google_drive`, `github`, `notion`, `trello`, `slack`, `zoom` — or `other` for a generic link. | +| `url` | String | The address the link points to. Supply an HTTP or HTTPS URL; a value without a scheme is prefixed with `https://`. External links do not enforce service-specific URL patterns. | -```shell -curl -s -H "Authorization: Bearer $ACCESS_TOKEN" \ - -A "MyApp (yourname@example.com)" \ - --data-urlencode "door[service]=other" \ - --data-urlencode "door[url]=https://example.com" \ - --data-urlencode "door[title]=External link" \ - --data-urlencode "door[description]=Optional description" \ - https://3.basecampapi.com/$ACCOUNT_ID/buckets/1/dock/doors.json -``` +###### Optional parameters +| Param | Type | Description | +| ------------- | ------ | ----------- | +| `title` | String | The name shown in the External links section. Defaults to `Untitled` when omitted. | +| `description` | HTML | Rich-text description shown beneath the title. | +| `image` | Binary | A thumbnail image, uploaded as `multipart/form-data`. | -Update an external link ------------------------ +On success this endpoint returns `302 Found` redirecting to the project with an empty +response body, for every representation. The new external link's ID is **not** returned — +discover it via [List external links](#list-external-links). -* `PUT /buckets/1/dock/doors/2.json` updates the external link with ID `2` in the project with ID `1`. +###### Example JSON Request -Any of the [Create an external link](#create-an-external-link) parameters may be supplied. Like create, this endpoint expects `application/x-www-form-urlencoded` parameters with bracketed keys and returns `302 Found` redirecting to the project's dock edit page on success with an empty response body. +```json +{ + "door": { + "service": "figma", + "url": "https://www.figma.com/file/abc123/Design-system", + "title": "Design system", + "description": "
Shared Figma workspace
" + } +} +``` ###### Copy as cURL ```shell -curl -s -H "Authorization: Bearer $ACCESS_TOKEN" \ - -A "MyApp (yourname@example.com)" \ - -X PUT \ - --data-urlencode "door[title]=Updated title" \ - --data-urlencode "door[url]=https://example.com/new-path" \ - https://3.basecampapi.com/$ACCOUNT_ID/buckets/1/dock/doors/2.json +curl -s -H "Authorization: Bearer $ACCESS_TOKEN" -H "Content-Type: application/json" \ + -d '{"door":{"service":"figma","url":"https://www.figma.com/file/abc123/Design-system","title":"Design system","description":"
Shared Figma workspace
"}}' \ + https://3.basecampapi.com/$ACCOUNT_ID/buckets/1/dock/doors.json ``` +Rename an external link +----------------------- + +Renaming is a shared dock-tool operation: use [Update a tool][update_a_tool]. +`PUT /dock/tools/:id.json` with a `title` renames the external link and returns +`200 OK` with the recording envelope. This changes only the title — see below for the +`url`, `service`, and `description`. + +Change a URL, service, or description +------------------------------------- + +There is **no reliable JSON endpoint** for changing an external link's `url`, `service`, +or `description`. The door route `PUT /buckets/1/dock/doors/2.json` applies the change but +then returns `406 Not Acceptable` (the record is updated before content negotiation), so +it can't be depended on as a JSON API. Make these edits in the Basecamp web app, or trash +the external link and [create](#create-an-external-link) a new one. Trash an external link ---------------------- -* `DELETE /buckets/1/dock/doors/2.json` trashes the external link with ID `2` in the project with ID `1`. +* `DELETE /dock/tools/2.json` (or the legacy `DELETE /buckets/1/dock/doors/2.json`) + trashes the external link. -This endpoint will return `204 No Content` if successful. Trashed external links are soft-deleted: their `status` becomes `"deleted"` (visible in [Search](search.md#search) results) and they no longer appear in the project's External links section. +This soft-deletes the external link: its `status` becomes `"deleted"` and it no longer +appears in the project's External links section, but the record is not permanently +removed. This differs from [Trash a tool][trash_a_tool], which permanently removes a +regular tool — only the request shape is shared. + +This endpoint returns `204 No Content` if successful. ###### Copy as cURL ```shell -curl -s -H "Authorization: Bearer $ACCESS_TOKEN" \ - -A "MyApp (yourname@example.com)" \ +curl -s -H "Authorization: Bearer $ACCESS_TOKEN" -H "Content-Type: application/json" \ -X DELETE \ - https://3.basecampapi.com/$ACCOUNT_ID/buckets/1/dock/doors/2.json + https://3.basecampapi.com/$ACCOUNT_ID/dock/tools/2.json ``` + +[projects]: projects.md +[pagination]: ../README.md#pagination +[get_recordings]: recordings.md#get-recordings +[get_a_tool]: tools.md#get-a-tool +[update_a_tool]: tools.md#update-a-tool +[trash_a_tool]: tools.md#trash-a-tool diff --git a/sections/recordings.md b/sections/recordings.md index b6c4344..ad090ab 100644 --- a/sections/recordings.md +++ b/sections/recordings.md @@ -15,7 +15,7 @@ Get recordings * `GET /projects/recordings.json` will return a [paginated list][1] of records for the given `type` of recording. -**Required parameters**: `type`, which must be `Comment`, `Document`, `Kanban::Card`, `Kanban::Step`, `Message`, `Question::Answer`, `Schedule::Entry`, `Todo`, `Todolist`, `Upload`, or `Vault`. +**Required parameters**: `type`, which must be `Comment`, `Document`, `Door`, `Kanban::Card`, `Kanban::Step`, `Message`, `Question::Answer`, `Schedule::Entry`, `Todo`, `Todolist`, `Upload`, or `Vault`. _Optional query parameters_: