Basecamp
Basecamp API integration with managed OAuth. Manage projects, to-dos, messages, schedules, documents, and team collaboration. Use this skill when users want to create and manage projects, to-do lists,
Basecamp API integration with managed OAuth. Manage projects, to-dos, messages, schedules, documents, and team collaboration. Use this skill when users want to create and manage projects, to-do lists,
Real data. Real impact.
Emerging
Developers
Per week
Open source
Skills give you superpowers. Install in 30 seconds.
Access the Basecamp 4 API with managed OAuth authentication. Manage projects, to-dos, messages, schedules, documents, and team collaboration.
# List all projects python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://gateway.maton.ai/basecamp/projects.json') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF
https://gateway.maton.ai/basecamp/{resource}.json
The gateway proxies requests to
3.basecampapi.com/{account_id}/ and automatically injects your OAuth token and account ID.
Important: All Basecamp API URLs must end with
.json.
All requests require the Maton API key in the Authorization header:
Authorization: Bearer $MATON_API_KEY
Environment Variable: Set your API key as
MATON_API_KEY:
export MATON_API_KEY="YOUR_API_KEY"
Manage your Basecamp OAuth connections at
https://ctrl.maton.ai.
python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://ctrl.maton.ai/connections?app=basecamp&status=ACTIVE') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF
python <<'EOF' import urllib.request, os, json data = json.dumps({'app': 'basecamp'}).encode() req = urllib.request.Request('https://ctrl.maton.ai/connections', data=data, method='POST') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') req.add_header('Content-Type', 'application/json') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF
python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://ctrl.maton.ai/connections/{connection_id}') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF
Response:
{ "connection": { "connection_id": "71e313c8-9100-48c6-8ea1-6323f6fafd04", "status": "ACTIVE", "creation_time": "2026-02-08T03:12:39.815086Z", "last_updated_time": "2026-02-08T03:12:59.259878Z", "url": "https://connect.maton.ai/?session_token=...", "app": "basecamp", "metadata": {} } }
Open the returned
url in a browser to complete OAuth authorization.
python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://ctrl.maton.ai/connections/{connection_id}', method='DELETE') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF
If you have multiple Basecamp connections, specify which one to use with the
Maton-Connection header:
python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://gateway.maton.ai/basecamp/projects.json') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') req.add_header('Maton-Connection', '71e313c8-9100-48c6-8ea1-6323f6fafd04') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF
If omitted, the gateway uses the default (oldest) active connection.
GET /basecamp/my/profile.json
Response:
{ "id": 51197030, "name": "Chris Kim", "email_address": "chris@example.com", "admin": true, "owner": true, "time_zone": "America/Los_Angeles", "avatar_url": "https://..." }
GET /basecamp/people.json
Response:
[ { "id": 51197030, "name": "Chris Kim", "email_address": "chris@example.com", "admin": true, "owner": true, "employee": true, "time_zone": "America/Los_Angeles" } ]
GET /basecamp/people/{person_id}.json
GET /basecamp/projects/{project_id}/people.json
GET /basecamp/projects.json
Response:
[ { "id": 46005636, "status": "active", "name": "Getting Started", "description": "Quickly get up to speed with everything Basecamp", "created_at": "2026-02-05T22:59:26.087Z", "url": "https://3.basecampapi.com/6153810/projects/46005636.json", "dock": [...] } ]
GET /basecamp/projects/{project_id}.json
The project response includes a
dock array with available tools (message_board, todoset, vault, chat, schedule, etc.). Each dock item has:
id: The tool's IDname: Tool type (e.g., "todoset", "message_board")enabled: Whether the tool is activeurl: Direct URL to access the toolPOST /basecamp/projects.json Content-Type: application/json{ "name": "New Project", "description": "Project description" }
PUT /basecamp/projects/{project_id}.json Content-Type: application/json{ "name": "Updated Project Name", "description": "Updated description" }
DELETE /basecamp/projects/{project_id}.json
First, get the todoset ID from the project's dock:
GET /basecamp/buckets/{project_id}/todosets/{todoset_id}.json
GET /basecamp/buckets/{project_id}/todosets/{todoset_id}/todolists.json
Response:
[ { "id": 9550474442, "title": "Basecamp essentials", "description": "", "completed": false, "completed_ratio": "0/5", "url": "https://..." } ]
POST /basecamp/buckets/{project_id}/todosets/{todoset_id}/todolists.json Content-Type: application/json{ "name": "New Todo List", "description": "List description" }
GET /basecamp/buckets/{project_id}/todolists/{todolist_id}.json
GET /basecamp/buckets/{project_id}/todolists/{todolist_id}/todos.json
Response:
[ { "id": 9550474446, "content": "Start here", "description": "", "completed": false, "due_on": null, "assignees": [] } ]
POST /basecamp/buckets/{project_id}/todolists/{todolist_id}/todos.json Content-Type: application/json{ "content": "New todo item", "description": "Todo description", "due_on": "2026-02-15", "assignee_ids": [51197030] }
Response:
{ "id": 9555973289, "content": "New todo item", "completed": false }
PUT /basecamp/buckets/{project_id}/todos/{todo_id}.json Content-Type: application/json{ "content": "Updated todo", "description": "Updated description" }
POST /basecamp/buckets/{project_id}/todos/{todo_id}/completion.json
Returns 204 on success.
DELETE /basecamp/buckets/{project_id}/todos/{todo_id}/completion.json
GET /basecamp/buckets/{project_id}/message_boards/{message_board_id}.json
GET /basecamp/buckets/{project_id}/message_boards/{message_board_id}/messages.json
POST /basecamp/buckets/{project_id}/message_boards/{message_board_id}/messages.json Content-Type: application/json{ "subject": "Message Subject", "content": "<p>Message body with HTML</p>", "category_id": 123 }
GET /basecamp/buckets/{project_id}/messages/{message_id}.json
PUT /basecamp/buckets/{project_id}/messages/{message_id}.json Content-Type: application/json{ "subject": "Updated Subject", "content": "<p>Updated content</p>" }
GET /basecamp/buckets/{project_id}/schedules/{schedule_id}.json
GET /basecamp/buckets/{project_id}/schedules/{schedule_id}/entries.json
POST /basecamp/buckets/{project_id}/schedules/{schedule_id}/entries.json Content-Type: application/json{ "summary": "Team Meeting", "description": "Weekly sync", "starts_at": "2026-02-15T14:00:00Z", "ends_at": "2026-02-15T15:00:00Z", "all_day": false, "participant_ids": [51197030] }
PUT /basecamp/buckets/{project_id}/schedule_entries/{entry_id}.json Content-Type: application/json{ "summary": "Updated Meeting", "starts_at": "2026-02-15T15:00:00Z", "ends_at": "2026-02-15T16:00:00Z" }
GET /basecamp/buckets/{project_id}/vaults/{vault_id}.json
GET /basecamp/buckets/{project_id}/vaults/{vault_id}/documents.json
POST /basecamp/buckets/{project_id}/vaults/{vault_id}/documents.json Content-Type: application/json{ "title": "Document Title", "content": "<p>Document content with HTML</p>" }
GET /basecamp/buckets/{project_id}/vaults/{vault_id}/uploads.json
GET /basecamp/chats.json
GET /basecamp/buckets/{project_id}/chats/{chat_id}.json
GET /basecamp/buckets/{project_id}/chats/{chat_id}/lines.json
POST /basecamp/buckets/{project_id}/chats/{chat_id}/lines.json Content-Type: application/json{ "content": "Hello from the API!" }
GET /basecamp/buckets/{project_id}/recordings/{recording_id}/comments.json
POST /basecamp/buckets/{project_id}/recordings/{recording_id}/comments.json Content-Type: application/json{ "content": "<p>Comment text</p>" }
All content items (todos, messages, documents, etc.) are "recordings" that can be archived or trashed.
PUT /basecamp/buckets/{project_id}/recordings/{recording_id}/status/trashed.json
PUT /basecamp/buckets/{project_id}/recordings/{recording_id}/status/archived.json
PUT /basecamp/buckets/{project_id}/recordings/{recording_id}/status/active.json
GET /basecamp/templates.json
POST /basecamp/templates/{template_id}/project_constructions.json Content-Type: application/json{ "name": "New Project from Template", "description": "Description" }
Basecamp uses Link header pagination with
rel="next":
Response Headers:
Link: <https://3.basecampapi.com/.../page=2>; rel="next" X-Total-Count: 150
Follow the
Link header URL for the next page. When next is absent, you've reached the last page.
Important: Do not construct pagination URLs manually. Always use the URL provided in the
Link header.
A "bucket" is a project's content container. The bucket ID is the same as the project ID in URLs:
/buckets/{project_id}/todosets/{todoset_id}.json
Each project has a "dock" containing available tools. Always check that a tool is
enabled: true before using it:
{ "dock": [ {"name": "todoset", "id": 123, "enabled": true}, {"name": "message_board", "id": 456, "enabled": false} ] }
All content items (todos, messages, documents, comments, etc.) are "recordings" with:
status: "active", "archived", or "trashed"parent: navigation to containerconst response = await fetch( 'https://gateway.maton.ai/basecamp/projects.json', { headers: { 'Authorization': `Bearer ${process.env.MATON_API_KEY}` } } ); const projects = await response.json();
import os import requestsresponse = requests.get( 'https://gateway.maton.ai/basecamp/projects.json', headers={'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'} ) projects = response.json()
.json<div>, <p>, <strong>, <em>, <a>, <ul>, <ol>, <li> tagsjq or other commands, environment variables like $MATON_API_KEY may not expand correctly in some shell environments| Status | Meaning |
|---|---|
| 400 | Missing Basecamp connection or bad request |
| 401 | Invalid or missing Maton API key |
| 404 | Resource not found, deleted, or no access |
| 429 | Rate limited (check Retry-After header) |
| 507 | Account limit reached (e.g., project limit) |
| 5xx | Server error (retry with exponential backoff) |
MATON_API_KEY environment variable is set:echo $MATON_API_KEY
python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://ctrl.maton.ai/connections') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF
basecamp. For example:https://gateway.maton.ai/basecamp/projects.jsonhttps://gateway.maton.ai/projects.jsonNo automatic installation available. Please visit the source repository for installation instructions.
View Installation Instructions1,500+ AI skills, agents & workflows. Install in 30 seconds. Part of the Torly.ai family.
© 2026 Torly.ai. All rights reserved.