Basecamp Integration Guide
spectryn supports Basecamp 3 for syncing markdown specifications. This guide covers OAuth setup, account and project configuration, and the Todo vs Message mapping strategy.
Overview
The Basecamp adapter supports:
- ✅ Projects (epics), Todos and Messages (stories), and Todo items (subtasks)
- ✅ Status mapping via todo completion state
- ✅ Priority and story points (stored in notes)
- ✅ Comments sync
- ✅ Campfire (chat) integration
- ✅ Webhooks for real-time sync
- ✅ Message boards as alternative to todos
Quick Start
# Install spectryn
pip install spectryn
# Sync markdown to Basecamp
spectryn --markdown EPIC.md --tracker basecamp --executeConfiguration
Config File (YAML)
Create .spectryn.yaml:
# Basecamp connection settings
basecamp:
access_token: your-basecamp-access-token
account_id: "123456" # Basecamp account ID
project_id: "789012" # Basecamp project ID
api_url: https://3.basecampapi.com # Optional: defaults to Basecamp 3 API
use_messages_for_stories: false # Optional: use Messages instead of Todos
# Sync settings
sync:
execute: false # Set to true for live mode
verbose: trueConfig File (TOML)
Create .spectryn.toml:
[basecamp]
access_token = "your-basecamp-access-token"
account_id = "123456"
project_id = "789012"
api_url = "https://3.basecampapi.com"
use_messages_for_stories = false
[sync]
execute = false
verbose = trueEnvironment Variables
# Required
export BASECAMP_ACCESS_TOKEN=your-basecamp-access-token
export BASECAMP_ACCOUNT_ID=123456
export BASECAMP_PROJECT_ID=789012
# Optional
export BASECAMP_API_URL=https://3.basecampapi.com
export BASECAMP_USE_MESSAGES_FOR_STORIES=falseCLI Arguments
spectryn \
--markdown EPIC.md \
--tracker basecamp \
--basecamp-access-token your-token \
--basecamp-account-id 123456 \
--basecamp-project-id 789012 \
--executeOAuth Setup
Basecamp 3 uses OAuth 2.0 for authentication. You'll need to create an OAuth application and obtain an access token.
Step 1: Create OAuth Application
Log in to Basecamp
- Go to basecamp.com
- Sign in to your account
Navigate to Integrations
- Click on your account name (top right)
- Go to Settings → Integrations → OAuth Applications
- Or visit:
https://launchpad.37signals.com/integrations
Create New Application
- Click "New application" or "Create a new application"
- Fill in the application details:
- Name:
spectryn-sync(or your preferred name) - Description:
CLI tool for syncing markdown specifications to Basecamp - Redirect URI:
urn:ietf:wg:oauth:2.0:oob(for CLI applications) - Scopes: Select the permissions you need:
- ✅ Read - Read todos, messages, comments
- ✅ Write - Create and update todos, messages, comments
- ✅ Admin - Full access (if you need to manage projects)
- Name:
Save Application
- Click "Save" or "Create application"
- You'll receive a Client ID and Client Secret
Step 2: Obtain Access Token
There are two ways to get an access token:
Option A: Personal Access Token (Recommended for CLI)
Go to Account Settings
- Navigate to your account settings
- Go to "My info" → "API tokens" or visit:
https://3.basecampapi.com/YOUR_ACCOUNT_ID/people/me.json
Generate Token
- Click "Create a new token"
- Give it a name:
spectryn-sync - Select scopes (same as OAuth scopes)
- Copy the token immediately (shown only once)
Option B: OAuth 2.0 Flow (For Applications)
If you're building an application that needs OAuth:
Authorize Application
https://launchpad.37signals.com/authorization/new? type=web_server& client_id=YOUR_CLIENT_ID& redirect_uri=urn:ietf:wg:oauth:2.0:oob& response_type=codeGet Authorization Code
- User authorizes the application
- Copy the authorization code from the redirect
Exchange for Access Token
bashcurl -X POST https://launchpad.37signals.com/authorization/token \ -H "Content-Type: application/json" \ -d '{ "type": "web_server", "client_id": "YOUR_CLIENT_ID", "client_secret": "YOUR_CLIENT_SECRET", "redirect_uri": "urn:ietf:wg:oauth:2.0:oob", "code": "AUTHORIZATION_CODE" }'Use Access Token
- The response contains an
access_token - Use this token for API requests
- The response contains an
Step 3: Configure spectryn
Set the access token as an environment variable:
export BASECAMP_ACCESS_TOKEN=your-access-token-hereOr in your config file:
basecamp:
access_token: your-access-token-hereToken Permissions
| Scope | Required For |
|---|---|
| Read | Viewing todos, messages, comments |
| Write | Creating/updating todos, messages, comments |
| Admin | Managing projects, webhooks, Campfire |
Security
- Never commit tokens to version control
- Use environment variables or
.envfiles (add to.gitignore) - Rotate tokens regularly
- Use tokens with minimal required permissions
- Personal access tokens don't expire, but OAuth tokens may
Account and Project Configuration
Finding Your Account ID
The account ID is the numeric identifier for your Basecamp account.
Method 1: From API Response
bashcurl -H "Authorization: Bearer YOUR_TOKEN" \ https://3.basecampapi.com/people/me.jsonLook for
accountsarray - each account has anidfield.Method 2: From Basecamp URL
- When viewing a project, check the URL
- Format:
https://3.basecampapi.com/{ACCOUNT_ID}/projects/{PROJECT_ID} - The first number is your account ID
Method 3: From Basecamp Web Interface
- Go to your account settings
- The account ID may be visible in the URL or API settings
Finding Your Project ID
The project ID is the numeric identifier for a specific Basecamp project.
Method 1: From Project URL
- Open your Basecamp project in a web browser
- Check the URL:
https://3.basecampapi.com/{ACCOUNT_ID}/projects/{PROJECT_ID} - The project ID is the number after
/projects/
Method 2: List Projects via API
bashcurl -H "Authorization: Bearer YOUR_TOKEN" \ https://3.basecampapi.com/{ACCOUNT_ID}/projects.jsonEach project in the response has an
idfield.Method 3: From Basecamp Web Interface
- Go to your project
- Check the browser's developer tools → Network tab
- Look for API requests - the project ID appears in URLs
Configuration Example
basecamp:
access_token: ${BASECAMP_ACCESS_TOKEN}
account_id: "123456" # Your Basecamp account ID
project_id: "789012" # Your Basecamp project ID
api_url: https://3.basecampapi.com# Set environment variables
export BASECAMP_ACCESS_TOKEN=your-token
export BASECAMP_ACCOUNT_ID=123456
export BASECAMP_PROJECT_ID=789012Todo vs Message Mapping
Basecamp 3 offers two ways to represent stories: Todos and Messages. The adapter supports both, and you can choose which one fits your workflow.
Todos (Default)
Use Todos when:
- ✅ You need task tracking with completion status
- ✅ You want assignees and due dates
- ✅ You need subtasks (todo items)
- ✅ You're managing a backlog or sprint
Characteristics:
- Can be marked as completed/not completed
- Support assignees and due dates
- Organized in Todo Sets (lists)
- Can have subtasks (todo items within a todo)
Example:
### STORY-001: Implement Login Feature
**Status:** In Progress
**Story Points:** 5
**Assignee:** john@example.com
**Due Date:** 2024-12-31Creates a todo in Basecamp that can be:
- Assigned to team members
- Marked as completed
- Given a due date
- Broken down into subtasks
Messages
Use Messages when:
- ✅ You want discussion-focused content
- ✅ You need announcements or updates
- ✅ You're documenting decisions or proposals
- ✅ Completion status isn't important
Characteristics:
- Posted to Message Boards
- Organized by categories
- Better for discussions and documentation
- No completion status (always "Planned")
Example:
### STORY-001: Design System Proposal
**Status:** Planned
**Story Points:** 3Creates a message in Basecamp that:
- Appears in the project's message board
- Can be categorized
- Supports rich text content
- Encourages discussion via comments
Configuration
Choose your mapping strategy:
# Use Todos (default)
basecamp:
use_messages_for_stories: false
# Use Messages
basecamp:
use_messages_for_stories: trueMapping Summary
| spectryn Concept | Basecamp (Todos) | Basecamp (Messages) |
|---|---|---|
| Epic | Project or Todo Set | Project or Message Board Category |
| Story | Todo | Message |
| Subtask | Todo Item (within todo) | Not supported |
| Status | Completed/Not Completed | Always "Planned" |
| Priority | Stored in notes | Stored in content |
| Story Points | Stored in notes | Stored in content |
| Assignee | Supported | Not supported |
| Due Date | Supported | Not supported |
When to Use Each
Choose Todos if:
- You're managing a development backlog
- You need to track completion status
- Assignees and due dates are important
- You have subtasks to track
Choose Messages if:
- You're documenting decisions or proposals
- Discussion is more important than completion
- You want announcement-style updates
- You don't need task tracking
Switching Between Modes
You can switch between modes, but note:
- Existing todos won't become messages (and vice versa)
- You may need to manually migrate content
- Consider your team's workflow before switching
Status Mapping
Basecamp todos use a simple completion model. The adapter maps standard statuses:
| spectryn Status | Basecamp Todo Status |
|---|---|
| Done, Completed, Closed, Resolved | ✅ Completed |
| Planned, To Do, Backlog | ⬜ Not Completed |
| In Progress, In Review | ⬜ Not Completed (status in notes) |
| Blocked, On Hold | ⬜ Not Completed (status in notes) |
Note: Messages don't have completion status - they're always "Planned".
Priority and Story Points
Basecamp doesn't natively support priority or story points. The adapter stores these values in the notes field (for todos) or content field (for messages).
Format
The adapter stores metadata in this format:
**Priority:** High
**Story Points:** 5
Your description here...Extraction
When reading from Basecamp, the adapter extracts:
- Story points from patterns like:
Story Points: 5,SP: 5,Points: 5 - Priority from patterns like:
Priority: High
Updating
When updating story points or priority:
- The adapter preserves existing notes/content
- Removes old priority/story points entries
- Adds new entries in the standard format
Advanced Features
Campfire (Chat) Integration
Basecamp includes Campfire for real-time chat. The adapter supports:
# Get all Campfires
campfires = adapter.get_campfires()
# Send a message
adapter.send_campfire_message(
chat_id="chat123",
content="Story STORY-001 has been completed!"
)
# Get chat history
messages = adapter.get_campfire_messages(
chat_id="chat123",
since="2024-01-01T00:00:00Z",
limit=50
)Use cases:
- Automated notifications when stories are synced
- Status updates for team members
- Integration with CI/CD pipelines
Webhooks
Set up webhooks to receive real-time updates:
# Create webhook
webhook = adapter.create_webhook(
url="https://your-server.com/webhook",
events=["todo.created", "todo.updated", "message.created"],
description="Spectra sync webhook"
)
# List webhooks
webhooks = adapter.list_webhooks()
# Delete webhook
adapter.delete_webhook(webhook_id="webhook123")Supported Events:
todo.created,todo.updated,todo.completed,todo.uncompletedmessage.created,message.updatedcomment.created,comment.updatedtodo_list.created,todo_list.updated
Comments
Comments are synced bidirectionally:
- Comments added in Basecamp appear in markdown
- Comments in markdown are added to Basecamp todos/messages
Rate Limiting
Basecamp API has a rate limit of 40 requests per 10 seconds. The adapter:
- Automatically throttles requests
- Implements exponential backoff on rate limit errors
- Respects
Retry-Afterheaders
Examples
Basic Sync
# Dry run (preview changes)
spectryn --markdown EPIC.md --tracker basecamp
# Execute sync
spectryn --markdown EPIC.md --tracker basecamp --executeWith Custom Configuration
# .spectryn.yaml
basecamp:
access_token: ${BASECAMP_ACCESS_TOKEN}
account_id: "123456"
project_id: "789012"
use_messages_for_stories: false # Use todos
sync:
execute: true
update_source_file: true # Write tracker info back to markdownMarkdown Example
# Epic: User Authentication
## Stories
### STORY-001: Login Page
**Story Points:** 5
**Priority:** High
**Status:** In Progress
**As a** user
**I want** to log in with email and password
**So that** I can access my account
#### Acceptance Criteria
- [ ] Email and password fields are present
- [ ] Form validation works
- [ ] Error messages display correctly
#### Subtasks
- [ ] Design login form (STORY-001-T1)
- [ ] Implement authentication API (STORY-001-T2)
- [ ] Add error handling (STORY-001-T3)Troubleshooting
Common Issues
"Authentication failed"
- Verify your access token is correct
- Check that the token hasn't expired (OAuth tokens)
- Ensure the token has the necessary scopes (Read, Write, Admin)
- Verify the token format (should start with a long string, no special prefix)
"Account not found"
- Verify the account ID is correct (numeric string)
- Check that you have access to the account
- Ensure the account ID matches the token's account
"Project not found"
- Verify the project ID is correct (numeric string)
- Check that the project exists in the specified account
- Ensure you have access to the project
- Verify the project ID is from Basecamp 3 (not Basecamp 2)
"Todo list not found"
- Ensure the project has at least one Todo Set
- Create a Todo Set in Basecamp if none exist
- Check that you're using the correct project ID
"Cannot create subtask for message"
- Subtasks are only supported for todos, not messages
- Switch to todo mode:
use_messages_for_stories: false - Or create the parent as a todo instead of a message
Debug Mode
Enable verbose logging:
spectryn --markdown EPIC.md --tracker basecamp --verboseOr set in config:
sync:
verbose: trueTesting Connection
Test your configuration:
from spectryn.adapters.basecamp import BasecampAdapter
adapter = BasecampAdapter(
access_token="your-token",
account_id="123456",
project_id="789012",
dry_run=True
)
# Test connection
if adapter.test_connection():
print("✓ Connection successful")
user = adapter.get_current_user()
print(f"✓ Logged in as: {user.get('name')}")
else:
print("✗ Connection failed")API Reference
Endpoints Used
GET /people/me.json- Get current userGET /projects/{id}.json- Get projectGET /projects/{id}/todosets.json- Get todo listsGET /projects/{id}/todosets/{id}/todos.json- Get todosGET /projects/{id}/todos/{id}.json- Get todoPOST /projects/{id}/todosets/{id}/todos.json- Create todoPUT /projects/{id}/todos/{id}.json- Update todoGET /projects/{id}/messages.json- Get messagesGET /projects/{id}/messages/{id}.json- Get messagePOST /projects/{id}/messages.json- Create messageGET /projects/{id}/recordings/{id}/comments.json- Get commentsPOST /projects/{id}/recordings/{id}/comments.json- Create commentGET /projects/{id}/chats.json- Get CampfiresPOST /projects/{id}/chats/{id}/lines.json- Send Campfire messagePOST /projects/{id}/webhooks.json- Create webhook
Rate Limits
- 40 requests per 10 seconds per account
- Adapter automatically throttles to stay under limit
- Retries with exponential backoff on 429 errors
Best Practices
- Use Dry Run First: Always test with
--executeflag off first - Choose the Right Mode: Decide between Todos and Messages based on your workflow
- Backup Your Data: Export your Basecamp project before bulk operations
- Incremental Syncs: Sync frequently to avoid large changes
- Consistent Naming: Use consistent story point and priority formats in notes
- Webhooks: Set up webhooks for real-time sync if needed
- Campfire Notifications: Use Campfire for team notifications about syncs
See Also
- Configuration Guide - General configuration options
- Getting Started - Quick start guide
- Schema Reference - Markdown schema details
- Basecamp 3 API Documentation - Official API docs