🎁 Get the FREE AI Skills Starter Guide β€” Subscribe β†’
BytesAgainBytesAgain
πŸ¦€ ClawHub

Basecamp

by @byungkyu

Basecamp API integration with managed OAuth. Manage projects, to-dos, messages, schedules, documents, and team collaboration. Use this skill when users want...

Versionv1.0.3
Downloads4,240
Stars⭐ 5
TERMINAL
clawhub install basecamp

πŸ“– About This Skill


name: basecamp description: | 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, schedule events, or collaborate with teams in Basecamp. For other third party apps, use the api-gateway skill (https://clawhub.ai/byungkyu/api-gateway). Requires network access and valid Maton API key. metadata: author: maton version: "1.0" clawdbot: emoji: 🧠 requires: env: - MATON_API_KEY

Basecamp

Access the Basecamp 4 API with managed OAuth authentication. Manage projects, to-dos, messages, schedules, documents, and team collaboration.

Quick Start

# List all projects
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.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

Base URL

https://api.maton.ai/basecamp/{resource}.json

Maton 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.

Authentication

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"

Getting Your API Key

1. Sign in or create an account at maton.ai 2. Go to maton.ai/settings 3. Copy your API key

Connection Management

Manage your Basecamp OAuth connections at https://api.maton.ai.

List Connections

python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.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

Create Connection

python <<'EOF'
import urllib.request, os, json
data = json.dumps({'app': 'basecamp'}).encode()
req = urllib.request.Request('https://api.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

Get Connection

python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.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": "{connection_id}",
    "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.

Delete Connection

python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.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

Specifying Connection

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://api.maton.ai/basecamp/projects.json')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Maton-Connection', '{connection_id}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF

If you have multiple connections, always include this header to ensure requests go to the intended account.

Security & Permissions

  • Access is scoped to projects, to-dos, messages, schedules, documents, and team collaboration within the connected Basecamp account.
  • All write operations require explicit user approval. Before executing any create, update, or delete call, confirm the target resource and intended effect with the user.
  • API Reference

    User Info

    #### Get Current User

    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://..."
    }
    

    People Operations

    #### List People

    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 Person

    GET /basecamp/people/{person_id}.json
    

    #### List Project Members

    GET /basecamp/projects/{project_id}/people.json
    

    Project Operations

    #### List Projects

    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 Project

    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 ID
  • name: Tool type (e.g., "todoset", "message_board")
  • enabled: Whether the tool is active
  • url: Direct URL to access the tool
  • #### Create Project

    POST /basecamp/projects.json
    Content-Type: application/json

    { "name": "New Project", "description": "Project description" }

    #### Update Project

    PUT /basecamp/projects/{project_id}.json
    Content-Type: application/json

    { "name": "Updated Project Name", "description": "Updated description" }

    #### Delete (Trash) Project

    DELETE /basecamp/projects/{project_id}.json
    

    To-Do Operations

    #### Get Todoset

    First, get the todoset ID from the project's dock:

    GET /basecamp/buckets/{project_id}/todosets/{todoset_id}.json
    

    #### List Todolists

    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://..."
      }
    ]
    

    #### Create Todolist

    POST /basecamp/buckets/{project_id}/todosets/{todoset_id}/todolists.json
    Content-Type: application/json

    { "name": "New Todo List", "description": "List description" }

    #### Get Todolist

    GET /basecamp/buckets/{project_id}/todolists/{todolist_id}.json
    

    #### List Todos

    GET /basecamp/buckets/{project_id}/todolists/{todolist_id}/todos.json
    

    Response:

    [
      {
        "id": 9550474446,
        "content": "Start here",
        "description": "",
        "completed": false,
        "due_on": null,
        "assignees": []
      }
    ]
    

    #### Create Todo

    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
    }
    

    #### Update Todo

    PUT /basecamp/buckets/{project_id}/todos/{todo_id}.json
    Content-Type: application/json

    { "content": "Updated todo", "description": "Updated description" }

    #### Complete Todo

    POST /basecamp/buckets/{project_id}/todos/{todo_id}/completion.json
    

    Returns 204 on success.

    #### Uncomplete Todo

    DELETE /basecamp/buckets/{project_id}/todos/{todo_id}/completion.json
    

    Message Board Operations

    #### Get Message Board

    GET /basecamp/buckets/{project_id}/message_boards/{message_board_id}.json
    

    #### List Messages

    GET /basecamp/buckets/{project_id}/message_boards/{message_board_id}/messages.json
    

    #### Create Message

    POST /basecamp/buckets/{project_id}/message_boards/{message_board_id}/messages.json
    Content-Type: application/json

    { "subject": "Message Subject", "content": "

    Message body with HTML

    ", "category_id": 123 }

    #### Get Message

    GET /basecamp/buckets/{project_id}/messages/{message_id}.json
    

    #### Update Message

    PUT /basecamp/buckets/{project_id}/messages/{message_id}.json
    Content-Type: application/json

    { "subject": "Updated Subject", "content": "

    Updated content

    " }

    Schedule Operations

    #### Get Schedule

    GET /basecamp/buckets/{project_id}/schedules/{schedule_id}.json
    

    #### List Schedule Entries

    GET /basecamp/buckets/{project_id}/schedules/{schedule_id}/entries.json
    

    #### Create Schedule Entry

    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] }

    #### Update Schedule Entry

    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" }

    Vault (Documents & Files) Operations

    #### Get Vault

    GET /basecamp/buckets/{project_id}/vaults/{vault_id}.json
    

    #### List Documents in Vault

    GET /basecamp/buckets/{project_id}/vaults/{vault_id}/documents.json
    

    #### Create Document

    POST /basecamp/buckets/{project_id}/vaults/{vault_id}/documents.json
    Content-Type: application/json

    { "title": "Document Title", "content": "

    Document content with HTML

    " }

    #### List Uploads in Vault

    GET /basecamp/buckets/{project_id}/vaults/{vault_id}/uploads.json
    

    Campfire (Chat) Operations

    #### List All Campfires

    GET /basecamp/chats.json
    

    #### Get Campfire

    GET /basecamp/buckets/{project_id}/chats/{chat_id}.json
    

    #### List Campfire Lines (Messages)

    GET /basecamp/buckets/{project_id}/chats/{chat_id}/lines.json
    

    #### Create Campfire Line

    POST /basecamp/buckets/{project_id}/chats/{chat_id}/lines.json
    Content-Type: application/json

    { "content": "Hello from the API!" }

    Comments Operations

    #### List Comments on Recording

    GET /basecamp/buckets/{project_id}/recordings/{recording_id}/comments.json
    

    #### Create Comment

    POST /basecamp/buckets/{project_id}/recordings/{recording_id}/comments.json
    Content-Type: application/json

    { "content": "

    Comment text

    " }

    Recording Status Operations

    All content items (todos, messages, documents, etc.) are "recordings" that can be archived or trashed.

    #### Trash Recording

    PUT /basecamp/buckets/{project_id}/recordings/{recording_id}/status/trashed.json
    

    #### Archive Recording

    PUT /basecamp/buckets/{project_id}/recordings/{recording_id}/status/archived.json
    

    #### Unarchive Recording

    PUT /basecamp/buckets/{project_id}/recordings/{recording_id}/status/active.json
    

    Templates Operations

    #### List Templates

    GET /basecamp/templates.json
    

    #### Create Project from Template

    POST /basecamp/templates/{template_id}/project_constructions.json
    Content-Type: application/json

    { "name": "New Project from Template", "description": "Description" }

    Pagination

    Basecamp uses Link header pagination with rel="next":

    Response Headers:

    Link: ; 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.

    Key Concepts

    Buckets and Projects

    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
    

    Dock

    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}
      ]
    }
    

    Recordings

    All content items (todos, messages, documents, comments, etc.) are "recordings" with:

  • status: "active", "archived", or "trashed"
  • parent: navigation to container
  • Unique IDs that can be used across endpoints
  • Code Examples

    JavaScript

    const response = await fetch(
      'https://api.maton.ai/basecamp/projects.json',
      {
        headers: {
          'Authorization': Bearer ${process.env.MATON_API_KEY}
        }
      }
    );
    const projects = await response.json();
    

    Python

    import os
    import requests

    response = requests.get( 'https://api.maton.ai/basecamp/projects.json', headers={'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'} ) projects = response.json()

    Notes

  • All API paths must end with .json
  • Maton automatically injects the account ID
  • Uses Basecamp 4 API (bc3-api)
  • Timestamps are in ISO 8601 format
  • HTML content uses
    ,

    , , , ,

  • πŸ’‘ Examples

    # List all projects
    python <<'EOF'
    import urllib.request, os, json
    req = urllib.request.Request('https://api.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
    

    πŸ“‹ Tips & Best Practices

  • All API paths must end with .json
  • Maton automatically injects the account ID
  • Uses Basecamp 4 API (bc3-api)
  • Timestamps are in ISO 8601 format
  • HTML content uses