Integrate Bolt.new with Trello using your API key and token from trello.com/app-key and the Trello REST API. Build custom Kanban boards, fetch cards from any board, create cards from Bolt forms, and move cards between lists — all through a Next.js API route that keeps your credentials server-side. Trello's query-parameter auth is one of the simplest patterns in any productivity API.
Building Custom Kanban Boards and Card Automations with Trello and Bolt.new
Trello's REST API gives you full access to your boards, lists, cards, checklists, members, and attachments. With this API you can build experiences that Trello's own interface does not offer — embedded board views for stakeholders who should not have a Trello account, automated card creation triggered by form submissions or external events, custom reporting dashboards aggregating card data across multiple boards, and workflow automations that move cards based on business logic in your app.
Trello uses a two-part authentication system that is simpler than most productivity APIs. You get an API key tied to your developer account, and then generate a token that grants your application access to your boards and data. For personal use, no OAuth flow is required — you can generate a token for yourself directly at trello.com/app-key. For apps where other users authenticate with their own Trello accounts, Trello provides a standard OAuth 1.0a flow, but for the vast majority of Bolt integration use cases the simple key-plus-token approach is sufficient.
Because the Trello integration uses entirely outbound HTTP requests, you can build and test the full feature set — reading boards, fetching cards, creating cards, moving cards — inside Bolt's WebContainer without deploying first. Trello webhooks, which push real-time notifications when cards move or change, are the only feature requiring a deployed public URL. For dashboards that refresh on a schedule, polling every 30 seconds is a clean alternative that works in development.
Integration method
Bolt generates the Trello integration through conversation — you describe the board view or card automation you want and Bolt writes the API route and React component code. Trello uses a simple API key plus token combination passed as query parameters, making it one of the easiest APIs to authenticate. All API calls go through server-side Next.js routes to keep credentials out of the browser bundle.
Prerequisites
- A Trello account with at least one board containing lists and cards
- Your Trello API key (from trello.com/app-key — log in to Trello first)
- A Trello API token generated from the same page (click 'Generate a Token' link on trello.com/app-key)
- A Next.js project in Bolt.new (prompt 'Create a Next.js app' to get started)
- Your board ID (visible in the Trello board URL: trello.com/b/{boardId}/{board-name})
Step-by-step guide
Get your Trello API key and token
Get your Trello API key and token
Trello uses a two-part authentication system: an API key that identifies your developer application, and a token that grants access to your specific account data. Both are needed for every API call. To get your API key, navigate to trello.com/app-key while logged into Trello. You will see your personal API key on this page — it is a 32-character alphanumeric string. This key is tied to your Trello account and persists until you regenerate it. To generate a token, click the 'Generate a Token' link on the same trello.com/app-key page. Trello will ask you to authorize the application and choose an expiration time. For personal automation tools, select '30 days' or 'Never expires'. After clicking Allow, you will see a 64-character token string — copy it immediately as this is the only time it is shown. Unlike most modern APIs that use OAuth 2.0 Bearer tokens, Trello passes both the key and token as URL query parameters on every request. This means every API URL looks like: https://api.trello.com/1/boards/{id}?key={apiKey}&token={token}. This is convenient but requires extra care: never construct Trello API URLs in client-side React components, since the key and token would be visible in browser network tabs. Always call Trello through your server-side Next.js API routes. Because the board ID is just a public identifier (not a credential), you can safely store it as a NEXT_PUBLIC_ variable if needed, but for consistency keep all Trello-related configuration in server-side .env variables.
Create a Next.js app with a Trello integration setup. Add a .env.local file with TRELLO_API_KEY, TRELLO_TOKEN, and TRELLO_BOARD_ID as placeholder variables. Create a /api/trello/board route that fetches the board name and all its lists using the Trello REST API. Pass the API key and token as query parameters.
Paste this in Bolt.new chat
1// .env.local2TRELLO_API_KEY=your_32_char_api_key3TRELLO_TOKEN=your_64_char_token4TRELLO_BOARD_ID=your_board_id_from_urlPro tip: Your Trello board ID is the short string in the board URL between /b/ and the board name — for example, in trello.com/b/AbCd1234/my-project, the board ID is AbCd1234. Copy it before starting.
Expected result: Your .env.local file is configured, and calling /api/trello/board returns the board name, ID, and an array of list objects with their IDs and names.
Fetch boards, lists, and cards
Fetch boards, lists, and cards
Trello's API is organized around three main resources: boards, lists, and cards. To build a board view, you need data from all three levels. The most efficient approach is to fetch all lists and their cards in a single API call using Trello's nested resource pattern — append /lists?cards=open to any board endpoint to get all lists with their cards embedded in the response. The board endpoint GET /1/boards/{boardId} accepts a fields parameter to limit which board properties are returned. For lists and cards, GET /1/boards/{boardId}/lists?cards=open returns all lists with each list containing a cards array. Card objects include: id, name, desc (description), due, dueComplete (boolean), labels (array of label objects with name and color), members (array of member IDs), idList (the list this card belongs to), url (link to card in Trello), pos (position within the list), and closed (archived status). Trello label colors are standard names: green, yellow, orange, red, purple, blue, sky, lime, pink, black. Labels also have a name property that you set in the Trello board settings. Use these to build color-coded UI elements in your React components. For member avatars, you need a separate call to GET /1/boards/{boardId}/members to get member details including avatarHash. The avatar URL pattern is: https://trello-members.s3.amazonaws.com/{memberId}/{avatarHash}/50.png. Since avatars require a separate API call and count against rate limits, cache them after the first fetch. All these API calls are outbound HTTP requests that work perfectly in Bolt's WebContainer preview. You can see your Trello boards rendered in your Bolt app without deploying.
Build a /api/trello/board-data route that fetches all lists and cards for my Trello board in one call. Also fetch all board members. Return the data as a nested structure: { board: {name, id}, lists: [{id, name, pos, cards: [{id, name, due, dueComplete, labels, members}]}], members: [{id, fullName, avatarHash}] }. Build a Kanban board React component that displays this data as columns with cards.
Paste this in Bolt.new chat
1// app/api/trello/board-data/route.ts2import { NextResponse } from 'next/server';34const TRELLO_API = 'https://api.trello.com/1';5const KEY = process.env.TRELLO_API_KEY;6const TOKEN = process.env.TRELLO_TOKEN;7const BOARD_ID = process.env.TRELLO_BOARD_ID;89function trelloParams(extra: Record<string, string> = {}) {10 return new URLSearchParams({ key: KEY!, token: TOKEN!, ...extra }).toString();11}1213export async function GET() {14 try {15 const [boardRes, listsRes, membersRes] = await Promise.all([16 fetch(`${TRELLO_API}/boards/${BOARD_ID}?${trelloParams({ fields: 'name,id,url' })}` ),17 fetch(`${TRELLO_API}/boards/${BOARD_ID}/lists?${trelloParams({ cards: 'open', card_fields: 'name,desc,due,dueComplete,labels,idMembers,pos,url' })}` ),18 fetch(`${TRELLO_API}/boards/${BOARD_ID}/members?${trelloParams({ fields: 'fullName,avatarHash,id' })}` ),19 ]);2021 if (!boardRes.ok || !listsRes.ok || !membersRes.ok) {22 throw new Error('Trello API error');23 }2425 const [board, lists, members] = await Promise.all([26 boardRes.json(),27 listsRes.json(),28 membersRes.json(),29 ]);3031 // Sort lists by position32 lists.sort((a: { pos: number }, b: { pos: number }) => a.pos - b.pos);3334 return NextResponse.json({ board, lists, members });35 } catch (error) {36 return NextResponse.json(37 { error: error instanceof Error ? error.message : 'Unknown error' },38 { status: 500 }39 );40 }41}Pro tip: Use Promise.all() to fetch board, lists, and members in parallel rather than sequentially. Three parallel requests complete almost as fast as one, cutting your board load time by roughly 60%.
Expected result: Calling /api/trello/board-data returns a structured JSON object with all lists sorted by position, cards nested within each list, and member details. The Kanban board component renders your Trello board as interactive columns.
Create cards, update them, and move them between lists
Create cards, update them, and move them between lists
Creating a Trello card requires a POST to /1/cards with at minimum the idList field (the list to create the card in). Optional fields: name (card title), desc (description text, supports Markdown), due (ISO 8601 datetime string for due dates), idLabels (array of label IDs from the board), idMembers (array of member IDs to assign), pos (position: 'top', 'bottom', or a positive float for specific positioning). To get label IDs for your board (needed when creating cards with specific labels), call GET /1/boards/{boardId}/labels. Each label has an id, name, and color. Store these IDs — they are stable and you can hardcode them after fetching once. Moving a card between lists uses PUT /1/cards/{cardId} with the idList field set to the destination list ID. You can also update card name, description, due date, and completion status in the same PUT call by including those fields. Archiving (not permanently deleting) a card uses PUT /1/cards/{cardId} with closed: true. This is the Trello equivalent of soft-delete — the card still exists and can be unarchived. Permanent deletion uses DELETE /1/cards/{cardId} and cannot be undone. For adding comments to cards, POST to /1/cards/{cardId}/actions/comments with a text field. Comments are visible in the card's activity feed in Trello. All these mutation operations work from Bolt's WebContainer since they are outbound HTTP requests. Only Trello webhooks — where Trello pushes card change events to your server URL — require a deployed application. For apps that only need to read and write data to Trello (not receive real-time push notifications), no deployment is required for a fully functional integration.
Add card creation and management to my Trello integration. Create a /api/trello/cards/create POST route that creates a card with: idList (required), name, desc, due, idLabels (array), and idMembers (array). Create a /api/trello/cards/[id]/move POST route that moves a card to a new list (accepts newListId). Add a card creation form to my Kanban board with a 'Add Card' button at the bottom of each list column.
Paste this in Bolt.new chat
1// app/api/trello/cards/create/route.ts2import { NextRequest, NextResponse } from 'next/server';34const TRELLO_API = 'https://api.trello.com/1';5const KEY = process.env.TRELLO_API_KEY;6const TOKEN = process.env.TRELLO_TOKEN;78export async function POST(request: NextRequest) {9 const { idList, name, desc, due, idLabels, idMembers } = await request.json();1011 if (!idList || !name) {12 return NextResponse.json(13 { error: 'idList and name are required' },14 { status: 400 }15 );16 }1718 const params = new URLSearchParams({19 key: KEY!,20 token: TOKEN!,21 idList,22 name,23 pos: 'bottom',24 });2526 if (desc) params.set('desc', desc);27 if (due) params.set('due', new Date(due).toISOString());28 if (idLabels?.length) params.set('idLabels', idLabels.join(','));29 if (idMembers?.length) params.set('idMembers', idMembers.join(','));3031 const response = await fetch(`${TRELLO_API}/cards`, {32 method: 'POST',33 headers: { 'Content-Type': 'application/x-www-form-urlencoded' },34 body: params.toString(),35 });3637 if (!response.ok) {38 const error = await response.json();39 return NextResponse.json({ error }, { status: response.status });40 }4142 const card = await response.json();43 return NextResponse.json({ id: card.id, name: card.name, url: card.url, shortUrl: card.shortUrl });44}Pro tip: Trello's card creation API accepts parameters as URL-encoded form data (application/x-www-form-urlencoded), not JSON. Use URLSearchParams to build the body and set the Content-Type header accordingly. Sending JSON will result in 400 errors.
Expected result: The Add Card form at the bottom of each Kanban column creates new cards in the corresponding Trello list. Cards appear immediately in both your Bolt app (after the component refetches) and in the Trello web interface.
Deploy and set up Trello webhooks for real-time updates
Deploy and set up Trello webhooks for real-time updates
While polling every 30-60 seconds is adequate for most Trello dashboard use cases, webhooks give you real-time updates when cards move, get created, or are modified — essential for apps where multiple people are working on the same board simultaneously. Trello webhooks work differently from most services: instead of registering a webhook URL through a web interface, you create webhooks via the Trello API itself. Send a POST to https://api.trello.com/1/webhooks/ with your API key and token as query parameters, and a JSON body containing callbackURL (your webhook endpoint URL), idModel (the board, list, or card ID to watch), and description. Deploy your Bolt app first using the Publish button or Bolt's Netlify integration. After deployment, your app has a stable public URL. Create the Trello webhook by calling your own webhook registration API route, which internally calls the Trello API with your deployed callback URL. The webhook payload Trello sends contains an action object describing what changed: action.type (like updateCard, createCard, moveCardToList), action.data (the full change data including old and new values), action.memberCreator (who made the change), and the board, list, and card objects involved. Trello expects a 200 response within 30 seconds — acknowledge immediately and process asynchronously if needed. Trello also sends a HEAD request to your webhook URL to verify it exists before activating the webhook. Your handler must respond to HEAD requests with 200 as well — Next.js does this automatically if you only define a POST export in the route file, since unhandled methods return 405, not 200. Add an explicit HEAD handler that returns 200 to ensure webhook registration succeeds. Note that Bolt's WebContainer development environment cannot receive inbound webhook requests since it runs inside the browser and has no public URL. Test webhooks after deploying to Netlify or Vercel.
Add Trello webhook support to my app. Create a /api/trello/webhook POST route that handles Trello webhook events. Also add a HEAD method handler that returns 200 (required for Trello webhook verification). Handle updateCard and createCard events by logging the card name and change type. Create a /api/trello/webhooks/register POST route that registers a webhook with Trello for my board ID, pointing to my deployed webhook URL from a WEBHOOK_BASE_URL environment variable.
Paste this in Bolt.new chat
1// app/api/trello/webhook/route.ts2import { NextRequest, NextResponse } from 'next/server';34// HEAD request: required for Trello webhook verification5export async function HEAD() {6 return new NextResponse(null, { status: 200 });7}89export async function POST(request: NextRequest) {10 const payload = await request.json();11 const { action } = payload;1213 if (!action) {14 return NextResponse.json({ received: true });15 }1617 const { type, data } = action;1819 switch (type) {20 case 'createCard':21 console.log(`New card created: "${data.card.name}" in list "${data.list.name}"`);22 break;23 case 'updateCard':24 if (data.listAfter) {25 console.log(`Card "${data.card.name}" moved from "${data.listBefore.name}" to "${data.listAfter.name}"`);26 }27 break;28 case 'commentCard':29 console.log(`Comment added to "${data.card.name}": ${data.text}`);30 break;31 default:32 break;33 }3435 return NextResponse.json({ received: true });36}Pro tip: Trello webhooks fire for every action on the watched board — including your own app's actions. Add logic to detect and ignore actions made by your own API token to prevent processing your own changes as if they were external events.
Expected result: After deploying and registering the webhook, your app receives real-time POST requests from Trello whenever cards are created, moved, or updated. The server logs show the card name and change type for each event.
Common use cases
Embedded read-only board view for clients
Build a read-only view of a Trello board that clients or stakeholders can access without needing a Trello account. The view displays all lists and cards with color-coded labels, due dates, and member avatars — giving visibility without edit access.
Build a Trello board viewer page in Next.js. Fetch all lists and cards for a board ID using the Trello API. Display the lists as columns in a Kanban layout, with cards inside each column showing: card name, label color chips, due date (red if overdue), and assigned member avatars. Make the whole view read-only with no drag-and-drop. Auto-refresh every 60 seconds.
Copy this prompt to try it in Bolt.new
Automated card creation from a customer intake form
When a customer submits an intake form on your website — for a service request, support ticket, or project brief — automatically create a Trello card in the designated 'New Requests' list with the form data, attach the customer's email, and assign it to the appropriate team member based on the request type.
Add a Trello integration to my customer intake form. When someone submits the form with: company name, request type (design/dev/consulting), description, and budget range, create a Trello card in list ID [LIST_ID] with the company name as the card name, the description and budget as the card description, and add a label based on request type (design=purple, dev=blue, consulting=green). Assign to my user ID.
Copy this prompt to try it in Bolt.new
Card status tracker with progress reporting
Build a dashboard that tracks cards across a Trello board's lists and calculates completion metrics — how many cards are in each stage, average time cards spend in each list, and weekly throughput of completed cards. Useful for Agile teams tracking sprint progress.
Build a Trello sprint metrics page that fetches all cards from a board and groups them by list. For each list, show: total card count, cards due this week, and cards with no due date. Add a completion chart using Recharts showing the distribution of cards across lists. Calculate and display a throughput metric: cards moved to the 'Done' list in the last 7 days using card activity data.
Copy this prompt to try it in Bolt.new
Troubleshooting
All Trello API calls return 401 Unauthorized or 'invalid token'
Cause: The API key or token is incorrect, expired (if you chose a 30-day expiration), or the token was revoked. Trello also returns 401 if the key or token are passed in the request body or as headers instead of as query parameters.
Solution: Verify that both TRELLO_API_KEY and TRELLO_TOKEN in your .env match the current values from trello.com/app-key. Tokens with 30-day expiration need periodic regeneration. If you chose 'Never expires' and still get 401, visit trello.com/1/members/me?key={key}&token={token} directly in your browser — if that returns data, your credentials are valid and the issue is in how your code passes them.
1// Credentials must be query parameters, not headers or body:2const url = `https://api.trello.com/1/boards/${boardId}?key=${KEY}&token=${TOKEN}`;3const response = await fetch(url); // No Authorization header neededCard creation returns 400 Bad Request with 'invalid id' for idList
Cause: The list ID provided in the idList field does not exist or belongs to a different board than expected. Trello list IDs are 24-character hex strings — using a board ID or card ID instead of a list ID causes this error.
Solution: Call GET /api/trello/board-data to retrieve the current list IDs from your board. Each list has a unique 24-character id field. Verify that the list ID in your request matches one of those values. List IDs do not change unless the list is deleted and recreated.
Trello webhook registration fails with 'URL is not reachable'
Cause: Trello sends a HEAD request to your callbackURL to verify it is accessible before activating the webhook. If your URL returns a non-200 status (or is not reachable), webhook registration fails. This commonly happens because your app is not deployed yet, or the webhook route only handles POST without a HEAD handler.
Solution: Deploy your app to Netlify or Vercel before registering the webhook — Bolt's WebContainer has no public URL. Add an explicit HEAD method handler to your webhook route that returns 200. Verify your deployed URL is accessible by opening it in a browser.
1// Add HEAD handler to your webhook route:2export async function HEAD() {3 return new NextResponse(null, { status: 200 });4}Best practices
- Never expose your Trello API key or token in client-side code — always pass them only in server-side Next.js API routes where they cannot be read from browser network tabs.
- Cache board structure data (lists, labels, members) on the server and refresh it every few minutes rather than on every request — this data changes rarely and Trello enforces rate limits of 100 requests per 10 seconds.
- Use the card_fields parameter when fetching cards to request only the fields you need — omitting large fields like attachments and actions significantly reduces response size and speeds up your dashboard.
- Add a HEAD method handler to your Trello webhook route that returns 200 — this is required for Trello's webhook verification request during registration and is easy to forget.
- Store board IDs and list IDs in your .env rather than hardcoding them in your API routes — this makes it easy to switch between a development board and production board without code changes.
- Implement exponential backoff for retry logic — if a Trello API call fails with 429 (rate limited) or a 5xx server error, wait 1 second before the first retry, then 2 seconds, then 4 seconds.
- For shared team boards, be careful with token-based authentication — the token you generate represents your user account. Any actions taken via the API (creating cards, adding comments) will appear as coming from you, not from the authenticated app user.
Alternatives
ClickUp offers a more comprehensive workspace hierarchy with docs, goals, time tracking, and multiple views beyond Kanban, while Trello is simpler and faster for visual board management.
Asana provides stronger project portfolio management and timeline views with a well-documented REST API, better suited for teams that need more structure than Trello's open board model.
Jira is the enterprise standard for software teams with deep sprint planning, backlog management, and developer tool integrations — more complex than Trello but more powerful for engineering workflows.
Monday.com uses a GraphQL API that enables complex cross-board queries and a more structured data model, better suited for teams that need flexible board configurations beyond Trello's Kanban model.
Frequently asked questions
How do I connect Bolt.new to Trello?
Get your API key from trello.com/app-key and generate a personal token on the same page. Add both as TRELLO_API_KEY and TRELLO_TOKEN in your .env.local file. Use Bolt chat to generate a Next.js API route that calls the Trello REST API, passing the key and token as query parameters on every request. Trello API calls are outbound HTTP requests that work in Bolt's WebContainer preview without deploying.
Does Bolt.new support Trello webhooks?
Trello webhooks require a publicly accessible URL that can receive POST requests — Bolt's WebContainer development environment runs in the browser and cannot receive incoming connections. You need to deploy your app to Netlify or Vercel first, then register the webhook using the Trello API with your deployed URL. For development testing, a polling approach (refreshing every 30-60 seconds) is a simpler alternative.
Can I test the Trello integration in Bolt's preview before deploying?
Yes, for all read and write operations. Fetching boards and cards, creating cards, moving cards, adding comments, and archiving cards all work in Bolt's WebContainer since they are outbound HTTP requests. The only limitation is receiving incoming Trello webhooks, which require a deployed public URL.
How do I find the Trello board ID and list IDs I need?
Your board ID is in the URL when you have a board open in Trello: trello.com/b/{boardId}/{board-name}. For list IDs, call the Trello API endpoint GET /1/boards/{boardId}/lists with your key and token, or use the /api/trello/board-data route you build in this tutorial — it returns all list IDs along with their names.
What is Trello's API rate limit?
Trello enforces a rate limit of 100 requests per 10 seconds per token. For dashboard applications loading board data on page load, this is almost never a concern. For bulk operations like creating many cards at once, add a small delay (100-200ms) between requests to avoid hitting the limit.
Can multiple users connect their own Trello accounts to my Bolt app?
Yes, but it requires implementing OAuth 1.0a so each user authenticates with their own Trello credentials. This is significantly more complex than the single-user API key approach. For personal tools and internal team apps, a single set of credentials (your API key and token) that acts on behalf of one account is usually sufficient. The Trello developer documentation covers the OAuth flow for multi-user apps.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation