# How to Integrate Retool with Basecamp

- Tool: Retool
- Difficulty: Intermediate
- Time required: 30 minutes
- Last updated: April 2026

## TL;DR

Connect Retool to Basecamp by creating a REST API Resource using Basecamp's OAuth 2.0 token as a Bearer authorization header. Once connected, query Basecamp projects, to-do lists, messages, and campfire threads to build a cross-project management hub that aggregates communication and task data for executive reporting.

## Build a Basecamp Project Hub in Retool

Basecamp's strength is its simplicity — one place for to-dos, messages, files, and chat. But that simplicity becomes a limitation when you need cross-project visibility. Operations leaders and executives often need to see the status of all active projects at a glance: which have overdue to-dos, which had no activity this week, which teams are overwhelmed. Basecamp's native interface requires clicking into each project individually, making portfolio-level reporting tedious.

Basecamp's API v2 and v3 (for Basecamp 3) provide programmatic access to all project data. Authentication uses OAuth 2.0, and Basecamp's API is organized around 'buckets' — their term for projects. Every data object (to-do list, message board, campfire) lives inside a bucket and is referenced by its bucket ID. Understanding this structure is key to writing effective Basecamp queries in Retool.

Retool's REST API Resource handles Basecamp perfectly. Configure the base URL with your Basecamp account ID once, store the OAuth token as a Bearer header, and you have server-side access to all your projects. Build a dashboard that shows all active projects, their recent activity, to-do completion rates, and upcoming deadlines — the kind of executive summary that would take hours to compile manually from Basecamp's native interface.

## Before you start

- A Basecamp 3 account with projects you want to access (this guide covers Basecamp 3; Basecamp 2 has a similar but separate API)
- Your Basecamp account ID (visible in the Basecamp URL after logging in: https://3.basecamp.com/{accountId}/)
- A Basecamp OAuth 2.0 access token — obtained via Basecamp's OAuth flow or using a personal access token for development
- A Retool account (Cloud or self-hosted) with permission to create Resources
- Basic familiarity with Retool's query editor and component bindings

## Step-by-step guide

### 1. Obtain a Basecamp OAuth 2.0 access token

Basecamp uses OAuth 2.0 for all API access. For a Retool integration where you're connecting your own Basecamp account to a private internal tool, the most practical approach is to obtain a personal access token via Basecamp's developer portal.

Navigate to https://launchpad.37signals.com/integrations and sign in with your Basecamp account. Click Register your app. Fill in the application name (e.g., Retool Integration), website URL, redirect URI (can be https://localhost for personal use), and the products you want to access (select Basecamp 3).

After registering, you'll receive a Client ID and Client Secret. For personal use, you can obtain an access token by visiting: https://launchpad.37signals.com/authorization/new?type=web_server&client_id=YOUR_CLIENT_ID&redirect_uri=YOUR_REDIRECT_URI. Complete the OAuth flow and capture the access token from the redirect.

For production tools used by a team, implement a full OAuth 2.0 flow using Retool's Custom Auth or have each user authenticate individually. For a simpler starting point, use the token obtained from the authorization flow above.

Find your Basecamp account ID by logging into Basecamp and checking the URL: https://3.basecamp.com/{accountId}/. Note this ID — it goes into the base URL for your Retool resource.

**Expected result:** You have a Basecamp OAuth 2.0 access token and your Basecamp account ID ready to configure in Retool.

### 2. Create the Basecamp REST API Resource in Retool

In Retool, navigate to the Resources tab and click Add Resource. Select REST API from the connector list.

Name: Basecamp API

Base URL: https://3.basecamp.com/YOUR_ACCOUNT_ID

Replace YOUR_ACCOUNT_ID with your actual Basecamp account ID (the number from the URL). All Basecamp API endpoints are scoped to your account ID, so including it in the base URL keeps your query paths clean.

Authentication: Retool's REST API resource doesn't have a dedicated OAuth Bearer option in all versions, so add it as a Header. Click Add Header. Key: Authorization. Value: Bearer YOUR_ACCESS_TOKEN.

If using a Retool Configuration Variable (recommended), go to Settings → Configuration Variables first, create BASECAMP_ACCESS_TOKEN with your token value, mark it as secret, then use the value: Bearer {{ retoolContext.configVars.BASECAMP_ACCESS_TOKEN }}.

Also add a required User-Agent header: Key: User-Agent, Value: RetoolIntegration (youremail@company.com). Basecamp requires a descriptive User-Agent identifying your application and contact — requests without a proper User-Agent may be rejected.

Click Create Resource. Test with a GET request to /projects.json — it should return an array of your Basecamp projects.

**Expected result:** The Basecamp API resource is created. A test GET /projects.json returns your Basecamp project list in JSON format.

### 3. Fetch all projects and to-do lists

Create a query named getProjects. Set method to GET and path to /projects.json. Basecamp returns all projects the authenticated user can access, including name, description, status, and when it was last updated. Active projects have a status of 'active'; archived projects show 'archived'.

The response array includes each project's id (the bucket ID), name, description, last_updated_at, and an app_url. The id field is what you'll use in all subsequent queries to access that project's data.

Create a Select component bound to getProjects and let users filter to a specific project. Add a transformer that extracts only active projects:

Once you have a project selected, query its to-do lists. Create a getToDoLists query: GET /buckets/{{ select_project.value }}/todolists.json. This returns all to-do lists in the selected project. Each list has an id, title, completed_ratio, and links to individual to-do items.

For the executive dashboard showing all projects at once, you can't use the project selector approach. Instead, use a JavaScript query that calls getProjects, then loops through the project IDs and fetches to-do stats for each. For 5-10 projects this is feasible; for 20+ projects, use Retool Workflows to avoid browser timeout issues.

```
// Transformer for project list with to-do stats
const projects = data || [];
return projects
  .filter(p => p.status === 'active')
  .map(project => ({
    id: project.id,
    name: project.name,
    description: project.description || '',
    last_updated: new Date(project.updated_at).toLocaleDateString(),
    app_url: project.app_url,
    purpose: project.purpose || 'company',
    bookmarked: project.bookmarked || false
  }));
```

**Expected result:** The getProjects query returns active Basecamp projects in a flat format. The project Select dropdown populates, and selecting a project triggers getToDoLists.

### 4. Query to-do items and messages

With a project selected and its to-do lists loaded, create a query to fetch individual to-do items. Create a getToDos query: GET /buckets/{{ select_project.value }}/todolists/{{ select_todolist.value }}/todos.json.

Query parameters to add:
- status: active (show only open todos; use 'archived' for completed)
- page: {{ pagination.offset / 20 + 1 }} (Basecamp paginates at 20 items per page)

Each to-do item has a content (the task description), assignees (array of user objects), due_on (ISO date string), completed (boolean), and creator. Note that Basecamp uses due_on (date) not a full datetime.

For message boards, create a getMessages query: GET /buckets/{{ select_project.value }}/message_boards/{{ getMessageBoard.data[0].id }}/messages.json. You first need to fetch the message board ID for the project: GET /buckets/{{ select_project.value }}/message_board.json (singular, returns the message board object including its id).

For Campfire (chat), query: GET /buckets/{{ select_project.value }}/chats/{{ getCampfire.data.id }}/lines.json to get recent messages.

The key insight for building a cross-project view is that each tool (message board, to-do list, campfire) has its own endpoint. Build separate queries for each tool type and combine them in a JavaScript transformer or use tabs in your Retool UI to switch between views.

```
// Transformer for to-do items
const todos = data || [];
return todos.map(todo => ({
  id: todo.id,
  content: todo.content,
  status: todo.completed ? 'Completed' : 'Open',
  assignees: (todo.assignees || []).map(a => a.name).join(', ') || 'Unassigned',
  due_date: todo.due_on || 'No due date',
  is_overdue: todo.due_on ? new Date(todo.due_on) < new Date() && !todo.completed : false,
  creator: todo.creator?.name || '',
  created_at: new Date(todo.created_at).toLocaleDateString(),
  notes_count: todo.notes_count || 0,
  url: todo.app_url
}));
```

**Expected result:** The getToDos query returns a flat array of to-do items with completion status and assignees, ready for display in a Table component.

### 5. Fetch people and build the workload view

To build a cross-person workload dashboard, you first need the list of people in your Basecamp account. Create a getPeople query: GET /people.json. This returns all users in the account with their id, name, email_address, and avatar_url.

For project-specific membership, use: GET /projects/{{ select_project.value }}/people.json.

To build the workload aggregation across projects, create a JavaScript query named aggregateWorkload. This query fetches todos from all projects and groups them by assignee. For a small number of projects (5-10), this runs in the browser; for larger workloads, migrate to a Retool Workflow.

Create a Chart component to visualize workload distribution. Set the chart type to Bar, x-axis to assignee name, and y-axis to open task count. Connect it to your transformer output.

For the executive summary layout, use Retool's Stat components to show: Total Active Projects, Total Open To-Dos, Due This Week, Overdue. These give leadership the instant context they need before drilling into the Table below.

For complex multi-project dashboards combining Basecamp with other data sources like your CRM or database, RapidDev's team can help build the cross-resource architecture in Retool.

```
// JavaScript query to aggregate workload across projects
// Assumes getProjects.data is available
const projects = getProjects.data || [];
const allTodos = [];

for (const project of projects.slice(0, 10)) { // limit to 10 projects to avoid rate limits
  try {
    const listsResult = await fetch(
      `https://3.basecamp.com/YOUR_ACCOUNT_ID/buckets/${project.id}/todolists.json`,
      { headers: { 'Authorization': 'Bearer YOUR_TOKEN' } }
    );
    const lists = await listsResult.json();
    for (const list of lists.slice(0, 5)) {
      const todosResult = await fetch(
        `https://3.basecamp.com/YOUR_ACCOUNT_ID/buckets/${project.id}/todolists/${list.id}/todos.json?status=active`,
        { headers: { 'Authorization': 'Bearer YOUR_TOKEN' } }
      );
      const todos = await todosResult.json();
      todos.forEach(t => allTodos.push({ ...t, project_name: project.name, list_name: list.title }));
    }
  } catch(e) { console.log('Error for project', project.id, e); }
}

// Group by assignee
const byAssignee = {};
allTodos.forEach(todo => {
  const name = todo.assignees?.[0]?.name || 'Unassigned';
  if (!byAssignee[name]) byAssignee[name] = [];
  byAssignee[name].push(todo);
});

return Object.entries(byAssignee).map(([name, todos]) => ({
  assignee: name,
  total_open: todos.length,
  overdue: todos.filter(t => t.due_on && new Date(t.due_on) < new Date()).length
}));
```

**Expected result:** A workload Chart and Table showing open tasks per team member, with overdue counts highlighted. Leadership can immediately see who has the most work.

### 6. Add real-time project activity feed

Basecamp's recording endpoint provides a unified activity feed for any project. Create a getActivity query: GET /buckets/{{ select_project.value }}/recordings.json with query parameters:
- type: Todo (or Message, Comment, Upload, Document)
- status: active
- sort: created_at
- direction: desc
- page: 1

This returns a chronological list of recent activity in the project — new to-dos created, comments added, files uploaded, and more. Display this in a compact list component with creator avatar, action description, and timestamp.

For a true activity stream across ALL projects, use the global recording endpoint: GET /accounting/YOUR_ACCOUNT_ID/events.json which requires the Basecamp administrative token. Most teams will use the per-project version.

To calculate the 'last activity' metric shown in the project overview, use the updated_at field from the project itself — Basecamp updates this whenever anything changes in the project. Format it as a relative time ('3 days ago') using a simple JavaScript helper in your transformer.

Set up an Auto Refresh on your main queries (every 5 minutes) using Retool's query refresh interval setting so your dashboard stays current without users manually clicking Refresh.

```
// Transformer for activity feed with relative timestamps
const recordings = data || [];
const now = new Date();

function timeAgo(dateStr) {
  const date = new Date(dateStr);
  const diffMs = now - date;
  const diffMins = Math.floor(diffMs / 60000);
  const diffHours = Math.floor(diffMins / 60);
  const diffDays = Math.floor(diffHours / 24);
  if (diffMins < 60) return `${diffMins}m ago`;
  if (diffHours < 24) return `${diffHours}h ago`;
  return `${diffDays}d ago`;
}

return recordings.map(r => ({
  id: r.id,
  type: r.type,
  title: r.title || r.content || '(no title)',
  creator: r.creator?.name || '',
  created_at: timeAgo(r.created_at),
  url: r.app_url,
  project: r.bucket?.name || ''
}));
```

**Expected result:** A live activity feed showing recent Basecamp activity across the selected project, with relative timestamps and links to each item in Basecamp.

## Best practices

- Always include a descriptive User-Agent header in your Basecamp API Resource — it's required by Basecamp's API terms of service and requests without it may be rejected.
- Store Basecamp OAuth tokens in Retool Configuration Variables (Settings → Configuration Variables) marked as secrets, never hardcoded in resource headers.
- Use Basecamp's project status field to filter out archived projects in your dashboard — query with ?status=active to avoid cluttering views with old projects.
- Remember that Basecamp paginates at 20 items per page — implement pagination for any to-do list or message board query that might return more than 20 items.
- For cross-project aggregation of 10+ projects, use Retool Workflows with Loop blocks and configurable retry settings instead of in-app JavaScript queries to avoid browser timeouts.
- Cache the getPeople and getProjects queries for 10 minutes since they change infrequently — this reduces API calls and improves dashboard load time.
- When building activity feeds, prefer per-project recording queries over account-wide event feeds — the per-project endpoints require less access scope and are faster.
- Add Basecamp's app_url field as a clickable link in all Table columns so users can jump from the Retool dashboard directly to the relevant item in Basecamp.

## Use cases

### Build an executive cross-project status dashboard

Create a Retool dashboard that shows all active Basecamp projects with key metrics: total to-dos, completed to-dos, completion percentage, last activity date, and project owner. Leadership can see at a glance which projects are on track and which need attention, without logging into each project individually.

Prompt example:

```
Build a Retool dashboard showing all active Basecamp projects in a Table. Calculate completion percentage from todoitems count. Show project name, description, last activity date, and completion %. Add a Chart showing completion rates across all projects. Include a link to open each project in Basecamp.
```

### Build a to-do workload tracker by assignee

Build a Retool panel that aggregates all open to-dos across Basecamp projects, grouped by assignee. Team leads can see which people have the most outstanding work, identify bottlenecks, and redistribute tasks. This view is impossible in Basecamp's native UI which shows to-dos only per-list, not per-person across all projects.

Prompt example:

```
Build a Retool workload panel that fetches all to-do items across selected Basecamp projects and groups them by assignee. Show a bar chart of open tasks per person. In the Table below, show each person's tasks with project name, list name, due date, and status. Add a filter for overdue tasks only.
```

### Build a project communication archive search

Create a Retool tool that searches Basecamp message boards and campfire chat history across multiple projects. Useful for teams who need to find decisions, announcements, or discussions that happened weeks or months ago without manually scrolling through each project's message board.

Prompt example:

```
Build a Retool message search tool with a text input and Project dropdown. Query Basecamp message boards and campfire threads for the selected project. Show results in a Table with subject, author, date, project name, and a link to the message in Basecamp. Sort by most recent.
```

## Troubleshooting

### 403 Forbidden on all requests despite a valid access token

Cause: Basecamp requires a properly formatted User-Agent header. Requests without a descriptive User-Agent (including contact information) are rejected to prevent anonymous abuse of the API.

Solution: Add a User-Agent header to your Retool REST API Resource with a value like: YourAppName (youremail@company.com). Navigate to Resources → Basecamp API → Edit → Headers, add User-Agent with your contact information. This is a documented Basecamp API requirement.

### 404 Not Found when fetching project-specific resources like to-dos or messages

Cause: The bucket ID (project ID) in the URL path is incorrect, or you're using the wrong endpoint format. Basecamp uses 'buckets' as the URL segment for projects, not 'projects'.

Solution: Verify the URL format: /buckets/{projectId}/todolists.json — note it's 'buckets' not 'projects' in the path. Get the correct project ID from the getProjects.json response. Also ensure you're appending .json to all endpoint paths.

### Basecamp token stopped working after a few days

Cause: Basecamp OAuth 2.0 access tokens expire if the application is deauthorized, the user changes their password, or the token is revoked. Unlike some APIs, Basecamp tokens can also expire if unused for an extended period.

Solution: Implement token refresh using Basecamp's token endpoint. Access tokens can be refreshed using the refresh_token obtained during the initial OAuth flow. If you don't have a refresh token, re-authorize through the OAuth flow. For a longer-lived solution, use Retool's Custom Auth to handle automatic token refresh.

### Only seeing 20 results when the project has many more to-dos or messages

Cause: Basecamp paginates all list endpoints at 20 items per page by default. The API does not support increasing the page size.

Solution: Implement pagination using the page query parameter. Check the Link header in the response — it contains a rel=next URL when more pages exist. In Retool, use a Number input bound to a page variable, or implement a load-more pattern where clicking a button increments the page number and concatenates results into a stored variable.

```
// Paginating Basecamp results
// In your query, set: page = {{ pagination.offset / 20 + 1 }}
// In Table settings, enable server-side pagination with page size 20
```

## Frequently asked questions

### Does Retool have a native Basecamp connector?

No, Retool does not have a dedicated native connector for Basecamp. You connect via a REST API Resource using Basecamp's OAuth 2.0 Bearer token. This gives full access to Basecamp's project, to-do, message, and people endpoints through Retool's server-side proxy.

### Which version of Basecamp does this guide cover?

This guide covers Basecamp 3 using the API at https://3.basecamp.com. Basecamp 2 has a separate API at https://basecamp.com/api. The authentication method (OAuth 2.0) is the same, but endpoint paths and data structures differ between versions. Check which version your team uses by looking at the URL when logged in.

### Can I create Basecamp to-dos from Retool?

Yes. Use POST /buckets/{projectId}/todolists/{todolistId}/todos.json with a JSON body containing the content (task description), due_on (ISO date like '2024-03-15'), and assignee_ids (array of person IDs). The content field is required; all others are optional. You can also create to-do lists (POST /buckets/{projectId}/todoset/{{ todosetId }}/todolists.json) and post messages to message boards.

### How do I get the Basecamp account ID?

Log into Basecamp and check the URL in your browser address bar. It will be in the format https://3.basecamp.com/{accountId}/. The accountId is the number after the domain. You can also find it in the API authorization response — the accounts array in the OAuth token response lists all accounts the user has access to with their IDs.

### Can multiple Retool users share the same Basecamp connection?

Yes. Configure the Basecamp API Resource with a Bearer token from a service account (a dedicated Basecamp user for integrations). All Retool users who have access to the resource will use this shared token. If you need each Retool user to authenticate with their own Basecamp account, configure OAuth 2.0 per-user authentication in the Resource settings — Retool stores OAuth tokens per user.

---

Source: https://www.rapidevelopers.com/retool-integrations/basecamp
© RapidDev — https://www.rapidevelopers.com/retool-integrations/basecamp
