# How to Integrate Basecamp with V0

- Tool: V0
- Difficulty: Intermediate
- Time required: 45 minutes
- Last updated: March 2026

## TL;DR

To integrate Basecamp with V0 by Vercel, set up an OAuth2 flow to authenticate users with their Basecamp accounts, then fetch projects, to-dos, and messages through Next.js API routes. Store your Basecamp OAuth credentials in Vercel environment variables and use V0 to generate the project management dashboard UI.

## Build a Custom Basecamp Dashboard with V0 and Next.js

Basecamp's REST API (version 4 as of early 2026) exposes all of its core functionality — projects (called 'campfires' internally), to-do lists, messages, schedules, and files — through a well-documented JSON API. Combined with V0-generated React components, you can build custom views of Basecamp data that are tailored specifically to your team's workflow, rather than being limited to Basecamp's own interface.

The most common use case is a unified dashboard that pulls together information from multiple Basecamp projects in one view — something Basecamp's native app does not offer. Marketing teams might want to see all pending to-dos across every project, engineering managers might want a cross-project status board, or a client-facing portal might show project progress without exposing the full Basecamp admin interface.

Basecamp uses OAuth2 for API access, which requires registering your app in the Basecamp developer portal and implementing the authorization code flow. This is slightly more complex than API key authentication but allows real users to authorize your app with their own Basecamp accounts — essential for multi-user tools. For single-developer integrations or internal tools where you are the only user, you can also use personal access tokens to skip the full OAuth flow.

## Before you start

- A Basecamp account (Basecamp 4 is the current version — ensure your account is on Basecamp 4 or Basecamp 3, as the API differs between versions)
- A registered Basecamp OAuth2 application — register at integrate.37signals.com to get a Client ID and Client Secret
- A V0 account at v0.dev and a Vercel account for deployment
- Your application's redirect URI configured in the 37signals integration settings (your Vercel deployment URL + /api/auth/callback/basecamp)

## Step-by-step guide

### 1. Register Your App and Generate the Dashboard UI

Before writing any code, register your application with 37signals (the company behind Basecamp) at integrate.37signals.com. Click 'Register your application,' fill in your app name, your website URL, and your redirect URI. The redirect URI should be the URL of your Vercel deployment plus /api/basecamp/callback — for example, https://your-app.vercel.app/api/basecamp/callback. For local development, also add http://localhost:3000/api/basecamp/callback as an additional redirect URI. After registering, 37signals provides a Client ID and Client Secret — save both securely. Now open V0 and generate the dashboard UI. Describe the layout, the data you want to display, and the filters you need. Be specific about project cards, to-do list items, and navigation — V0 produces better results with detailed prompts. Push the generated code to GitHub via the V0 Git panel.

**Expected result:** A project management dashboard renders in the V0 preview with sidebar, metric cards, and to-do table using mock data. The UI is ready for real Basecamp data once the OAuth flow is implemented.

### 2. Implement the Basecamp OAuth2 Flow

The Basecamp API uses OAuth2 with the authorization code flow. This requires two API routes: one that redirects users to Basecamp to authorize your app, and one callback route that exchanges the authorization code for an access token. The Basecamp OAuth endpoints are at launchpad.37signals.com. The authorization URL is https://launchpad.37signals.com/authorization/new and the token exchange endpoint is https://launchpad.37signals.com/authorization/token. After a successful token exchange, Basecamp returns an access token, a refresh token, and a list of the user's accounts (they may belong to multiple Basecamp organizations). Store the access token and refresh token in a secure cookie or server-side session — never in localStorage or a non-HttpOnly cookie. For production apps, use a database like Neon (Vercel Marketplace) to persist tokens across serverless function invocations.

```
// app/api/basecamp/auth/route.ts — redirect to Basecamp for authorization
import { NextResponse } from 'next/server';

export async function GET() {
  const clientId = process.env.BASECAMP_CLIENT_ID;
  const redirectUri = process.env.BASECAMP_REDIRECT_URI; // e.g. https://yourapp.vercel.app/api/basecamp/callback

  if (!clientId || !redirectUri) {
    return NextResponse.json({ error: 'Basecamp OAuth not configured' }, { status: 500 });
  }

  const authUrl = new URL('https://launchpad.37signals.com/authorization/new');
  authUrl.searchParams.set('type', 'web_server');
  authUrl.searchParams.set('client_id', clientId);
  authUrl.searchParams.set('redirect_uri', redirectUri);

  return NextResponse.redirect(authUrl.toString());
}
```

**Expected result:** Visiting /api/basecamp/auth in the browser redirects users to the Basecamp authorization page at launchpad.37signals.com, where they can grant your app permission to access their account.

### 3. Create the Token Callback and Basecamp Data Routes

After the user authorizes your app on Basecamp's OAuth page, Basecamp redirects them back to your /api/basecamp/callback route with an authorization code. This callback route exchanges the code for an access token and stores it, then redirects the user to your dashboard. Once you have the access token, create a general Basecamp API proxy route that fetches projects, to-dos, messages, and other resources. All Basecamp API requests must include the Authorization: Bearer header with the access token and a User-Agent header identifying your app (required by 37signals). Add your Vercel environment variables: BASECAMP_CLIENT_ID, BASECAMP_CLIENT_SECRET, and BASECAMP_REDIRECT_URI. For a simpler personal integration, you can skip the full OAuth flow and use a personal access token from Basecamp's profile settings.

```
// app/api/basecamp/callback/route.ts — exchange code for token
import { NextRequest, NextResponse } from 'next/server';
import { cookies } from 'next/headers';

export async function GET(request: NextRequest) {
  const { searchParams } = new URL(request.url);
  const code = searchParams.get('code');

  if (!code) {
    return NextResponse.json({ error: 'No authorization code received' }, { status: 400 });
  }

  const tokenResponse = await fetch('https://launchpad.37signals.com/authorization/token', {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: new URLSearchParams({
      type: 'web_server',
      client_id: process.env.BASECAMP_CLIENT_ID ?? '',
      client_secret: process.env.BASECAMP_CLIENT_SECRET ?? '',
      redirect_uri: process.env.BASECAMP_REDIRECT_URI ?? '',
      code,
    }),
  });

  if (!tokenResponse.ok) {
    return NextResponse.json({ error: 'Token exchange failed' }, { status: 400 });
  }

  const tokenData = await tokenResponse.json();
  const cookieStore = cookies();
  cookieStore.set('basecamp_token', tokenData.access_token, {
    httpOnly: true,
    secure: process.env.NODE_ENV === 'production',
    maxAge: 60 * 60 * 24 * 14, // 14 days
    path: '/',
  });

  return NextResponse.redirect(new URL('/dashboard', request.url));
}
```

**Expected result:** After a user completes the Basecamp OAuth flow, they are redirected to your dashboard URL and an access token is stored in an HttpOnly cookie. Subsequent API route calls can read this token from the cookie to make authenticated Basecamp requests.

### 4. Add Vercel Environment Variables and Deploy

Add all required environment variables to your Vercel project. Open Vercel Dashboard → your project → Settings → Environment Variables and add the following: BASECAMP_CLIENT_ID (from integrate.37signals.com), BASECAMP_CLIENT_SECRET (same source, keep this secret), and BASECAMP_REDIRECT_URI (your Vercel deployment URL + /api/basecamp/callback, e.g. https://your-app.vercel.app/api/basecamp/callback). If you are also adding this redirect URI for preview deployments, you can add a Preview-environment-specific BASECAMP_REDIRECT_URI that uses your Vercel preview URL pattern. After adding the variables, trigger a redeployment. Once deployed, click the 'Connect Basecamp' button (or navigate to /api/basecamp/auth) to test the full OAuth flow. After authorizing, your dashboard should fetch and display your real Basecamp projects and to-dos.

```
# .env.local (do NOT commit)
BASECAMP_CLIENT_ID=your_client_id_here
BASECAMP_CLIENT_SECRET=your_client_secret_here
BASECAMP_REDIRECT_URI=http://localhost:3000/api/basecamp/callback
```

**Expected result:** The fully deployed app shows a 'Connect Basecamp' button for new users. Clicking it initiates the OAuth flow. After authorizing, users land on the dashboard with their real Basecamp projects displayed in the sidebar and their to-dos in the main content area.

## Best practices

- Store Basecamp OAuth tokens in HttpOnly secure cookies or a server-side database — never in localStorage, sessionStorage, or non-HttpOnly cookies. HttpOnly cookies are inaccessible to JavaScript and prevent token theft via XSS attacks.
- Implement token refresh proactively: store the token expiry time alongside the access token and check it before each API request. Refresh the token before it expires rather than handling 401 errors reactively.
- Always include the User-Agent header on every Basecamp API request — 37signals enforces this and will reject requests without it. Use a descriptive name and contact email in the format required by 37signals API documentation.
- Cache Basecamp API responses for data that changes infrequently, like project lists and to-do counts. Use Vercel KV (Upstash Redis) with a 60-second TTL to avoid hammering the Basecamp API on every dashboard page load.
- Use the account ID from the authorization response when constructing Basecamp API URLs. Users may belong to multiple Basecamp accounts — always use the correct account ID for the selected account.
- Handle Basecamp API rate limits gracefully. The API is rate-limited and will return 429 responses during heavy usage. Add retry logic with exponential backoff for rate limit errors.
- For internal tools where only you use the app, consider using Basecamp's personal access tokens (from your Basecamp profile settings) instead of implementing the full OAuth2 flow — it is much simpler and does not require registering an OAuth app.

## Use cases

### Cross-Project To-Do Dashboard

Display all open to-dos across multiple Basecamp projects in a single prioritized view. Team members can see their assignments without switching between project-by-project views in Basecamp, and managers get a bird's-eye view of all outstanding work.

Prompt example:

```
Create a to-do dashboard with a sidebar listing Basecamp projects, a main area showing to-dos filtered by the selected project with columns for task name, assigned person, and due date. Add filter buttons for All, Overdue, Due Today, and Upcoming. Use a checkbox to mark tasks complete. Fetch projects from /api/basecamp/projects and to-dos from /api/basecamp/todos.
```

### Client-Facing Project Progress Portal

Build a read-only progress portal that clients can access to see the status of their project without needing a Basecamp account. Show milestones, completed to-dos, and recent messages without exposing the full project administration interface.

Prompt example:

```
Build a client portal page showing a project header with name and start date, a progress bar based on completed vs total to-dos, a list of recent messages with author and date, and a milestone timeline. Keep the design clean and professional. Fetch from /api/basecamp/project/{id}/overview.
```

### Team Activity Feed

Create a real-time feed of recent activity across all Basecamp projects — new to-dos added, messages posted, and files uploaded. This is useful for managers who need to stay informed about team activity without checking each project individually.

Prompt example:

```
Design an activity feed page with a timeline of recent events, each showing an avatar, event description ('John added a to-do in Marketing Project'), timestamp, and a link to the item. Group events by day. Add a project filter dropdown. Fetch from /api/basecamp/events.
```

## Troubleshooting

### OAuth redirect returns 'redirect_uri_mismatch' error from Basecamp

Cause: The redirect URI in your OAuth request does not exactly match the URI registered in the 37signals integration settings. Even a trailing slash difference will cause this error.

Solution: Go to integrate.37signals.com, find your app, and verify the registered redirect URI exactly matches BASECAMP_REDIRECT_URI in your environment variables — including https:// vs http://, the exact path, and no trailing slash. For Vercel preview deployments, add a separate redirect URI for the preview domain.

### API requests return 401 even with a valid access token

Cause: The access token has expired (Basecamp tokens expire after approximately 2 weeks), or the Authorization header format is incorrect.

Solution: Implement token refresh logic using the refresh token stored alongside the access token. Check that your Authorization header is formatted as 'Bearer {access_token}' exactly — no extra spaces or characters. Verify the token has not expired by checking the stored expiry timestamp.

```
// Correct Authorization header format
const response = await fetch(basecampUrl, {
  headers: {
    'Authorization': `Bearer ${accessToken}`,
    'User-Agent': 'YourAppName (your@email.com)', // required by 37signals
    'Content-Type': 'application/json',
  },
});
```

### Basecamp API returns 'User-Agent required' or 403 error on all requests

Cause: 37signals requires a descriptive User-Agent header on all API requests. Requests without it are rejected.

Solution: Add a User-Agent header to all Basecamp API requests with your app name and contact email in the format 'YourAppName (contact@email.com)'. This is a firm requirement from 37signals, not optional.

```
headers: {
  'Authorization': `Bearer ${token}`,
  'User-Agent': 'MyBasecampDashboard (developer@example.com)',
}
```

## Frequently asked questions

### Which version of the Basecamp API should I use?

Use the Basecamp 4 API (also referred to as Basecamp 3 API in many places — the API URL uses 3.basecampapi.com). The documentation is at github.com/basecamp/bc3-api. Avoid the legacy Basecamp 2 API if your account is on Basecamp 3 or 4.

### Do I need a paid Basecamp account to use the API?

Yes, the Basecamp API requires an active paid Basecamp subscription. There is a 30-day free trial available, but after that you need a paid plan ($15/month for Basecamp Personal or $299/month for Basecamp for Business) to continue using the API.

### Can I use Basecamp API without OAuth if I am just building a personal tool?

Yes. If you are the only user of your V0 app and want to skip the OAuth flow, you can generate a personal access token from your Basecamp profile settings. Use this token directly in your API routes as a Bearer token. This is much simpler than OAuth2 but only works for a single user.

### How do I get the Basecamp account ID for API requests?

After completing the OAuth flow, make a GET request to https://launchpad.37signals.com/authorization.json with the access token in the Authorization header. The response includes an 'accounts' array. Each account has an 'id' field — this is your Basecamp account ID needed for all API endpoint URLs.

### Can I write data back to Basecamp, or is this read-only?

The Basecamp API supports both read and write operations. You can create to-dos, post messages, upload files, create comments, and update task status via POST, PUT, and DELETE requests. Your Next.js API routes can accept POST requests from your V0 components and forward them to the appropriate Basecamp write endpoints.

### What is the difference between integrating Basecamp vs Teamwork?

Basecamp is an opinionated all-in-one tool with a strong philosophy about how projects should be managed — flat structure, async-first, minimal notifications. Teamwork offers more traditional project management features like time tracking, budget tracking, and Gantt charts. Choose Basecamp if your team already uses it; choose Teamwork if you need more structured PM workflows.

---

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