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..ee24d25 --- /dev/null +++ b/sections/external_links.md @@ -0,0 +1,230 @@ +External links +============== + +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: + +- [List external links](#list-external-links) +- [Get a single external link](#get-a-single-external-link) +- [Create an external link](#create-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 + +List external links +------------------- + +* `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). + +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": 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" \ + "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][projects] + with ID `1`. + +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. + +###### Required parameters + +| 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. | + +###### 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`. | + +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). + +###### Example JSON Request + +```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" -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 /dock/tools/2.json` (or the legacy `DELETE /buckets/1/dock/doors/2.json`) + trashes the external link. + +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" -H "Content-Type: application/json" \ + -X DELETE \ + 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_: