Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 20 additions & 18 deletions sections/card_table_templates.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,16 +115,9 @@ Create a card table template
```
<!-- END POST PAYLOAD /template_library/card_tables.json -->

###### Copy as cURL

```shell
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" -H "Content-Type: application/json" \
-d '{"name":"Client onboarding"}' -X POST \
https://3.basecampapi.com/$ACCOUNT_ID/template_library/card_tables.json
```

A successful request returns `201 Created` with the new [card table](card_tables.md). Its `parent` is the library's card table container, never the library's dock: a card table only counts as a template when it lives in that container, so a card table can't be added to the template library as a [dock tool](tools.md).

###### Example JSON Response
<!-- START POST /template_library/card_tables.json -->
```json
{
Expand Down Expand Up @@ -485,6 +478,14 @@ A successful request returns `201 Created` with the new [card table](card_tables
```
<!-- END POST /template_library/card_tables.json -->

###### Copy as cURL

```shell
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" -H "Content-Type: application/json" \
-d '{"name":"Client onboarding"}' -X POST \
https://3.basecampapi.com/$ACCOUNT_ID/template_library/card_tables.json
```

Create a card table from a template
-----------------------------------

Expand All @@ -508,17 +509,10 @@ A `destination_parent_id` naming the dock recording is accepted instead, for cal
```
<!-- END POST PAYLOAD /template_library/copies.json (card table) -->

###### Copy as cURL

```shell
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" -H "Content-Type: application/json" \
-d '{"template_recording_id":1069480295,"destination_project_id":2085958504}' -X POST \
https://3.basecampapi.com/$ACCOUNT_ID/template_library/copies.json
```

The copy resource, its people confirmation step, and polling work exactly as for a [to-do list template](template_library.md#create-a-to-do-list-from-a-template). A completed copy includes the new card table as `destination_card_table`:

<!-- START GET /template_library/copies/2.json (card table) -->
###### Example JSON Response (completed copy)
<!-- START GET /template_library/copies/1.json (card table) -->
```json
{
"id": 1,
Expand Down Expand Up @@ -1057,4 +1051,12 @@ The copy resource, its people confirmation step, and polling work exactly as for
}
}
```
<!-- END GET /template_library/copies/2.json (card table) -->
<!-- END GET /template_library/copies/1.json (card table) -->

###### Copy as cURL

```shell
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" -H "Content-Type: application/json" \
-d '{"template_recording_id":1069480295,"destination_project_id":2085958504}' -X POST \
https://3.basecampapi.com/$ACCOUNT_ID/template_library/copies.json
```
9 changes: 6 additions & 3 deletions sections/event_feed.md
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ Error responses:
canonical filters preserved.

###### Example JSON Response

<!-- START GET /events.json -->
```json
{
"events": [
Expand All @@ -315,6 +315,7 @@ Error responses:
"position": "aBcD..."
}
```
<!-- END GET /events.json -->

###### Copy as cURL

Expand Down Expand Up @@ -443,7 +444,7 @@ position has seen none of the retained backlog, so that entry is exactly-once
continuation.

###### Example JSON Response

<!-- START GET /inbox.json -->
```json
{
"items": [
Expand All @@ -467,6 +468,7 @@ continuation.
"position": "aBcD..."
}
```
<!-- END GET /inbox.json -->

###### Copy as cURL

Expand Down Expand Up @@ -508,14 +510,15 @@ socket, so mint-per-connection is connector discipline, not server
enforcement. Every socket is bounded to a single subscription regardless.

###### Example JSON Response

<!-- START POST /events/stream_ticket.json -->
```json
{
"ticket": "aBcD...",
"expires_in": 120,
"url": "wss://chat.3.basecamp.com/195539477?ticket=aBcD..."
}
```
<!-- END POST /events/stream_ticket.json -->

###### Copy as cURL

Expand Down
8 changes: 4 additions & 4 deletions sections/people.md
Original file line number Diff line number Diff line change
Expand Up @@ -223,13 +223,13 @@ Join a project

No parameters. No request body.

This is the API equivalent of opening an all-access project in the web app and joining it yourself. It is **not** the same as [Update who can access a project](#update-who-can-access-a-project), which grants or revokes access for other people.
This is the API equivalent of opening an all-access project in the web app and joining it yourself. It is **not** the same as [Update who can access a project](#update-who-can-access-a-project), which grants or revokes access for the people you name.

Returns `201 Created` with an empty body if the join succeeded. After a successful join, an active project appears in [Get all projects](projects.md#get-all-projects) and [Get a project](projects.md#get-a-project) works for this person.

If the project doesn't exist, or its policy doesn't let the current person in, the API returns `404 Not Found`. The policy is checked first, so that includes people who already have access but aren't admitted by the policy, such as a client, or anyone other than an owner on an `invite` project. If the policy admits the person and they already have access, nothing changes and the response is a `302 Found` redirect to the project. Agent tokens get `403 Forbidden`.
If the project doesn't exist, or its policy doesn't let the current person in, the API returns `404 Not Found`. The policy is checked first, so that includes people who already have access but aren't admitted by the policy, such as a client, or anyone other than an owner on an `invite` project. If the policy admits the person and they already have access, nothing changes and the response is a `302 Found` redirect to the project. A token that acts as an agent itself gets `403 Forbidden`; a token a person delegated to an agent acts as that person.

`GET /projects.json` only lists projects the current person has already joined, so the ID of a project to join has to come from elsewhere: the project's web URL (`https://3.basecamp.com/$ACCOUNT_ID/projects/1`), or someone who can see the project. Reading a project, or most resources inside one, that the person hasn't joined but could returns `403 Forbidden` with the URL to join. For example, `GET /projects/1.json` for such a project returns:
`GET /projects.json` only lists projects the current person already has access to, so the ID of a project to join has to come from elsewhere: the project's web URL (`https://3.basecamp.com/$ACCOUNT_ID/projects/1`), or someone who can see the project. Reading a project, or most resources inside one, that the person doesn't have access to but could join returns `403 Forbidden` with the URL to join. For example, `GET /projects/1.json` for such a project returns:

###### Example JSON Response
<!-- START GET /projects/1.json (seek admission) -->
Expand All @@ -242,7 +242,7 @@ If the project doesn't exist, or its policy doesn't let the current person in, t
```
<!-- END GET /projects/1.json (seek admission) -->

`admission_url` has no `.json` extension: POST to it with `Accept: application/json`, or add `.json`, to get `201 Created`. Without either, the join still happens but the response is a `302` redirect. Most writes (`POST`, `PUT`, `DELETE`) inside an all-access project the person hasn't joined but could don't return `403`: they join the person to the project and then carry out the request. The join stays even if the request itself is then refused.
`admission_url` has no `.json` extension: POST to it with `Accept: application/json`, or add `.json`, to get `201 Created`. Without either, the join still happens but the response is a `302` redirect. Most writes (`POST`, `PUT`, `DELETE`) inside an all-access project the person doesn't have access to but could join don't return `403`: they join the person to the project and then carry out the request. The join stays even if the request itself is then refused.

###### Copy as cURL

Expand Down
27 changes: 14 additions & 13 deletions sections/template_library.md
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,7 @@ Answers `201 Created` with the template. Fill it in with the [to-do](todos.md) e
```shell
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"Client onboarding"}' -X POST \
-d '{"name":"New hire setup"}' -X POST \
https://3.basecampapi.com/$ACCOUNT_ID/template_library/todolists.json
```

Expand All @@ -379,16 +379,9 @@ A `destination_parent_id` naming the to-do set is accepted instead, for callers
```
<!-- END POST PAYLOAD /template_library/copies.json -->

###### Copy as cURL

```shell
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" -H "Content-Type: application/json" \
-d '{"template_recording_id":1069480314,"destination_project_id":2085958504}' -X POST \
https://3.basecampapi.com/$ACCOUNT_ID/template_library/copies.json
```

A successful request returns `201 Created` with a copy resource. Follow its `url` to track progress.

###### Example JSON Response
<!-- START POST /template_library/copies.json -->
```json
{
Expand All @@ -401,6 +394,14 @@ A successful request returns `201 Created` with a copy resource. Follow its `url
```
<!-- END POST /template_library/copies.json -->

###### Copy as cURL

```shell
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" -H "Content-Type: application/json" \
-d '{"template_recording_id":1069480314,"destination_project_id":2085958504}' -X POST \
https://3.basecampapi.com/$ACCOUNT_ID/template_library/copies.json
```

When the template contains assignments or completion subscriptions for people who do not have access to the destination project, the response is `422 Unprocessable Entity` and identifies the people who would be added:

<!-- START POST /template_library/copies.json (confirmation required) -->
Expand All @@ -423,14 +424,14 @@ Repeat the request with `adding_people_confirmed` set to `true` to grant those p
Get a template copy
-------------------

* `GET /template_library/copies/1.json` returns the current state of a template copy.
* `GET /template_library/copies/2.json` returns the current state of a template copy.

Only the person who started the copy can retrieve it. Requests from anyone else return `404 Not Found`, so poll with the same credentials that created the copy.

The status is `pending`, `processing`, `completed`, or `failed`. Poll the URL no more than once per second while the copy is pending or processing. A completed response includes the newly created to-do list.

###### Example JSON Response
<!-- START GET /template_library/copies/1.json -->
<!-- START GET /template_library/copies/2.json -->
```json
{
"id": 2,
Expand Down Expand Up @@ -510,11 +511,11 @@ The status is `pending`, `processing`, `completed`, or `failed`. Poll the URL no
}
}
```
<!-- END GET /template_library/copies/1.json -->
<!-- END GET /template_library/copies/2.json -->

###### Copy as cURL

```shell
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" \
https://3.basecampapi.com/$ACCOUNT_ID/template_library/copies/1.json
https://3.basecampapi.com/$ACCOUNT_ID/template_library/copies/2.json
```
2 changes: 1 addition & 1 deletion sections/timeline.md
Original file line number Diff line number Diff line change
Expand Up @@ -1155,7 +1155,7 @@ Each timeline event includes these fields:
| `url` | API URL to fetch the item |
| `app_url` | Link to view the item in Basecamp |
| `creator` | The [person][person] the action is attributed to |
| `performed_by` | The agent that carried out the action on the creator's behalf, as a [person][person] with `"personable_type": "Agent"`. Present only for [delegated events](events.md#delegated-events) |
| `performed_by` | The agent that carried out the action on the creator's behalf, as a [person][person] with `"personable_type": "Agent"`, or `"Tombstone"` once that agent has been deleted. Present only for [delegated events](events.md#delegated-events), so its presence, not the `personable_type`, marks an agent-performed action |
| `action` | Human-readable description of the action |
| `target` | The name of the parent container or item affected |
| `title` | Combined action and target as a complete sentence |
Expand Down