Skip to main content
RapidDev - Software Development Agency
replit-integrationsStandard API Integration

How to Integrate Replit with Trello

To integrate Replit with Trello, generate an API Key from trello.com/power-ups/admin and authorize a Token, store both in Replit Secrets (lock icon in sidebar), then call the Trello REST API to create cards, move them between lists, and manage boards. Register a webhook pointing to your deployed Replit app for real-time card change notifications.

What you'll learn

  • How to generate a Trello API Key and Token for authentication
  • How to store Trello credentials securely in Replit Secrets
  • How to read boards, lists, and cards from the Trello API
  • How to create, update, and move cards between lists programmatically
  • How to receive real-time Trello webhook events on a deployed Replit endpoint
Book a free consultation
4.9Clutch rating ⭐
600+Happy partners
17+Countries served
190+Team members
Intermediate17 min read15 minutesProductivityMarch 2026RapidDev Engineering Team
TL;DR

To integrate Replit with Trello, generate an API Key from trello.com/power-ups/admin and authorize a Token, store both in Replit Secrets (lock icon in sidebar), then call the Trello REST API to create cards, move them between lists, and manage boards. Register a webhook pointing to your deployed Replit app for real-time card change notifications.

Why Connect Replit to Trello?

Trello's simplicity is its strength β€” boards, lists, and cards map naturally to any workflow. But when your project management needs go beyond what Trello's built-in automations can handle, the Trello REST API lets you build custom integrations that automate card creation, status updates, and reporting in ways that Power-Ups and Butler rules cannot.

Common integration scenarios include: automatically creating a Trello card when a new support ticket arrives, moving cards between lists based on webhook events from other systems, building a custom reporting dashboard that aggregates data across multiple boards, or syncing Trello card status to a database so you can query project progress. Any time you want to create cards from code (form submissions, scheduled jobs, external triggers) or react to card changes programmatically, the Trello API is the tool.

Trello's API uses simple query parameter authentication β€” your API Key and Token are appended to every request URL. This is less secure than OAuth but significantly simpler for personal integrations and server-side code where the credentials are stored in Replit Secrets and never exposed to browsers. This tutorial walks through the full setup: generating credentials, making API calls, and receiving webhook events on a deployed Replit app.

Integration method

Standard API Integration

The Replit-Trello integration works by authenticating with a Trello API Key and Token stored in Replit Secrets, then calling the Trello REST API from your backend server to interact with boards, lists, and cards. API Key + Token authentication is simpler than OAuth for personal integrations and gives access to all boards the authorizing account can see. For event-driven workflows, you register a Trello webhook pointing to your deployed Replit app that fires whenever a card or board changes.

Prerequisites

  • A Trello account with at least one board created
  • A Replit account with a Node.js or Python Repl ready
  • Basic familiarity with REST APIs and HTTP requests
  • A deployed Replit app URL (needed for webhook registration β€” use Autoscale deployment)

Step-by-step guide

1

Generate Your Trello API Key and Token

Trello's authentication uses two credentials: an API Key (identifies your integration) and a Token (grants access to a specific Trello account's data). Both are required for every API call. To get your API Key, log into Trello and navigate to trello.com/power-ups/admin. Click 'New Power-Up' or find an existing one β€” even if you are not building a Power-Up, this is where Trello manages developer apps. Fill in the required fields (Power-Up Name: 'Replit Integration', Workspace: choose any, Iframe connector URL: leave blank for now). Click 'Create' and then click on your new app. Under the 'API Key' tab, you will see your API Key displayed. Click 'Show API Key' and copy it. Next, generate a Token. On the same API Key page, click the 'Token' link (shown in a note below the API Key). This opens an authorization page where Trello asks you to grant the app access to your account. Click 'Allow'. You will see a long Token string β€” copy it immediately as it is shown only once on this page. The Token you just generated grants read/write access to all boards, lists, and cards the authorizing Trello account can access. It does not expire unless you manually revoke it in Trello Settings > Apps. For integrations where you want read-only access or time-limited access, append &expiration=1day or &expiration=never to the token authorization URL and set &scope=read instead of &scope=read,write.

Pro tip: The API Key is associated with your developer app and can be shared across multiple integrations. The Token is per-account authorization β€” if you need your integration to act on behalf of multiple users, each user must authorize a separate Token.

Expected result: You have both a Trello API Key (32-character string) and a Token (64-character string) ready to store in Replit.

2

Store Credentials in Replit Secrets

Click the lock icon (πŸ”’) in the Replit sidebar to open the Secrets panel. Add two secrets: 1. TRELLO_API_KEY β€” your 32-character API Key from the Power-Up admin page 2. TRELLO_TOKEN β€” your 64-character Token from the authorization page Click 'Add Secret' after each one. These values are now encrypted with AES-256 and stored separately from your code. They will never appear in your file tree, version control history, or be visible to other users who fork your Repl. If you need to work with multiple Trello workspaces or use different tokens for different environments, you can add additional secrets like TRELLO_TOKEN_PROD and TRELLO_TOKEN_DEV and select the appropriate one with an environment variable check. You can also store frequently used IDs as secrets to avoid hardcoding them: - TRELLO_BOARD_ID β€” the ID of your main board (find it by adding .json to your board URL: trello.com/b/{boardId}/board-name.json) - TRELLO_LIST_ID_TODO β€” the ID of your 'To Do' list (find it from the board JSON or the Trello API) Access in code: - Node.js: process.env.TRELLO_API_KEY - Python: os.environ['TRELLO_API_KEY']

Pro tip: To find a board ID quickly, open the board in Trello, click 'Share' in the top right, then 'Export JSON' β€” the JSON file URL contains the board ID. Or add .json to the board's URL in your browser.

Expected result: TRELLO_API_KEY and TRELLO_TOKEN appear in the Replit Secrets panel with values hidden.

3

Read Boards, Lists, and Cards from the Trello API

The Trello REST API base URL is https://api.trello.com/1/. All requests append the API key and token as query parameters. This is simpler than bearer token authentication but means both values appear in request URLs β€” ensure you are always making these calls server-side (from your Replit backend), never from browser JavaScript where they would be visible in network logs. The code below provides both Node.js and Python examples for reading board structure and card data. Install the Python requests library if using Python: in the Replit Shell, run pip install requests.

trello-client.js
1// trello-client.js β€” Node.js Trello API client
2const BASE_URL = 'https://api.trello.com/1';
3
4function getAuthParams() {
5 const key = process.env.TRELLO_API_KEY;
6 const token = process.env.TRELLO_TOKEN;
7 if (!key || !token) throw new Error('TRELLO_API_KEY and TRELLO_TOKEN secrets required');
8 return `key=${key}&token=${token}`;
9}
10
11async function trelloGet(endpoint) {
12 const url = `${BASE_URL}${endpoint}${endpoint.includes('?') ? '&' : '?'}${getAuthParams()}`;
13 const response = await fetch(url);
14 if (!response.ok) {
15 const error = await response.text();
16 throw new Error(`Trello API ${response.status}: ${error}`);
17 }
18 return response.json();
19}
20
21async function trelloPost(endpoint, body) {
22 const url = `${BASE_URL}${endpoint}?${getAuthParams()}`;
23 const response = await fetch(url, {
24 method: 'POST',
25 headers: { 'Content-Type': 'application/json' },
26 body: JSON.stringify(body)
27 });
28 if (!response.ok) {
29 const error = await response.text();
30 throw new Error(`Trello API ${response.status}: ${error}`);
31 }
32 return response.json();
33}
34
35async function trelloPut(endpoint, body) {
36 const url = `${BASE_URL}${endpoint}?${getAuthParams()}`;
37 const response = await fetch(url, {
38 method: 'PUT',
39 headers: { 'Content-Type': 'application/json' },
40 body: JSON.stringify(body)
41 });
42 if (!response.ok) {
43 const error = await response.text();
44 throw new Error(`Trello API ${response.status}: ${error}`);
45 }
46 return response.json();
47}
48
49// Get all boards for the authenticated user
50async function getBoards() {
51 return trelloGet('/members/me/boards?fields=id,name,url');
52}
53
54// Get all lists on a board
55async function getLists(boardId) {
56 return trelloGet(`/boards/${boardId}/lists?fields=id,name,pos`);
57}
58
59// Get all cards in a list
60async function getCards(listId) {
61 return trelloGet(`/lists/${listId}/cards?fields=id,name,desc,due,labels,url`);
62}
63
64module.exports = { trelloGet, trelloPost, trelloPut, getBoards, getLists, getCards };

Pro tip: Use the ?fields= parameter on all Trello API endpoints to request only the fields you need. This reduces response payload size significantly β€” Trello card objects can contain 30+ fields by default.

Expected result: Calling getBoards() returns a JSON array of your Trello boards with IDs and names. getLists() returns the lists on a specific board.

4

Create and Manage Cards via the API

With the client module ready, build an Express server that exposes endpoints for creating, updating, and moving cards. Card creation requires at minimum a name and the ID of the list to add it to. Optionally, you can set a description, due date, labels, and members. The moveCard function is the most commonly used operation in automation workflows β€” it changes the list a card belongs to (e.g., moving from 'In Progress' to 'Done') without any other changes. Install Express if not already present: npm install express

server.js
1// server.js β€” Trello card management Express server
2const express = require('express');
3const { trelloPost, trelloPut, trelloGet, getBoards, getLists } = require('./trello-client');
4
5const app = express();
6app.use(express.json());
7
8// GET /boards β€” list all accessible boards
9app.get('/boards', async (req, res) => {
10 try {
11 const boards = await getBoards();
12 res.json({ boards });
13 } catch (err) {
14 res.status(500).json({ error: err.message });
15 }
16});
17
18// GET /boards/:boardId/lists β€” get lists on a board
19app.get('/boards/:boardId/lists', async (req, res) => {
20 try {
21 const lists = await getLists(req.params.boardId);
22 res.json({ lists });
23 } catch (err) {
24 res.status(500).json({ error: err.message });
25 }
26});
27
28// POST /cards β€” create a new card
29app.post('/cards', async (req, res) => {
30 try {
31 const { listId, name, description, dueDate, labelIds } = req.body;
32 if (!listId || !name) {
33 return res.status(400).json({ error: 'listId and name are required' });
34 }
35
36 const cardData = {
37 idList: listId,
38 name,
39 desc: description || '',
40 pos: 'bottom'
41 };
42
43 if (dueDate) cardData.due = dueDate; // ISO 8601 string
44 if (labelIds && labelIds.length > 0) {
45 cardData.idLabels = labelIds.join(',');
46 }
47
48 const card = await trelloPost('/cards', cardData);
49 res.json({
50 id: card.id,
51 name: card.name,
52 url: card.url,
53 shortLink: card.shortLink
54 });
55 } catch (err) {
56 res.status(500).json({ error: err.message });
57 }
58});
59
60// PUT /cards/:cardId/move β€” move card to a different list
61app.put('/cards/:cardId/move', async (req, res) => {
62 try {
63 const { targetListId } = req.body;
64 if (!targetListId) {
65 return res.status(400).json({ error: 'targetListId required' });
66 }
67
68 const updated = await trelloPut(`/cards/${req.params.cardId}`, {
69 idList: targetListId,
70 pos: 'bottom'
71 });
72 res.json({ success: true, cardId: updated.id, newList: updated.idList });
73 } catch (err) {
74 res.status(500).json({ error: err.message });
75 }
76});
77
78// PUT /cards/:cardId β€” update card details
79app.put('/cards/:cardId', async (req, res) => {
80 try {
81 const { name, description, dueComplete } = req.body;
82 const updates = {};
83 if (name) updates.name = name;
84 if (description !== undefined) updates.desc = description;
85 if (dueComplete !== undefined) updates.dueComplete = dueComplete;
86
87 const updated = await trelloPut(`/cards/${req.params.cardId}`, updates);
88 res.json({ success: true, card: { id: updated.id, name: updated.name } });
89 } catch (err) {
90 res.status(500).json({ error: err.message });
91 }
92});
93
94app.listen(3000, '0.0.0.0', () => {
95 console.log('Trello integration server running on port 3000');
96});

Pro tip: To find list IDs for your boards without writing code, use the Trello API Explorer at developer.atlassian.com/cloud/trello/rest/ or append .json to your board URL and search for 'id' inside the lists array in the response.

Expected result: POST /cards creates a new Trello card in the specified list and returns the card ID and URL. PUT /cards/:cardId/move successfully moves the card to a different list.

5

Set Up Trello Webhooks for Real-Time Card Events

Trello webhooks fire whenever something changes on a board or card β€” card moves, new comments, checklist completions, and more. Unlike other services that have a webhook configuration UI, Trello webhooks are created programmatically via the API. First, deploy your Replit app to get a stable URL. Click the Deploy button, choose 'Autoscale', and note your deployment URL (e.g., https://your-app.replit.app). Your webhook endpoint must be publicly accessible and must respond to Trello's initial HEAD request with a 200 status code. To create a webhook, send a POST request to the Trello webhooks API specifying the callback URL and the model ID to watch (a board ID, list ID, or card ID). The Python code below handles both the webhook registration and the event receiver.

trello_webhook.py
1# trello_webhook.py β€” Python webhook registration and handler
2import os
3import requests
4from flask import Flask, request, jsonify
5
6app = Flask(__name__)
7
8TRELLO_BASE = 'https://api.trello.com/1'
9
10def get_auth_params():
11 return {
12 'key': os.environ['TRELLO_API_KEY'],
13 'token': os.environ['TRELLO_TOKEN']
14 }
15
16def register_webhook(model_id, callback_url):
17 """Register a Trello webhook for a board or card ID."""
18 params = {**get_auth_params(),
19 'idModel': model_id,
20 'callbackURL': callback_url,
21 'description': 'Replit Integration Webhook'}
22 response = requests.post(f'{TRELLO_BASE}/webhooks', params=params)
23 response.raise_for_status()
24 return response.json()
25
26def list_webhooks():
27 """List all webhooks for the current token."""
28 params = get_auth_params()
29 response = requests.get(
30 f'{TRELLO_BASE}/tokens/{params["token"]}/webhooks',
31 params=params
32 )
33 return response.json()
34
35# Trello sends HEAD request to verify webhook URL β€” must return 200
36@app.route('/trello-webhook', methods=['HEAD'])
37def webhook_verify():
38 return '', 200
39
40# Handle incoming webhook events
41@app.route('/trello-webhook', methods=['POST'])
42def trello_webhook():
43 payload = request.json
44 if not payload:
45 return 'OK', 200
46
47 action = payload.get('action', {})
48 action_type = action.get('type', 'unknown')
49 data = action.get('data', {})
50
51 print(f'Trello event: {action_type}')
52
53 if action_type == 'createCard':
54 card_name = data.get('card', {}).get('name')
55 list_name = data.get('list', {}).get('name')
56 print(f'New card created: "{card_name}" in "{list_name}"')
57
58 elif action_type == 'updateCard':
59 card = data.get('card', {})
60 old = data.get('old', {})
61 if 'idList' in old:
62 # Card was moved between lists
63 print(f'Card moved: {card.get("name")} -> list {card.get("idList")}')
64 elif 'dueComplete' in old:
65 complete = card.get('dueComplete')
66 print(f'Card completion changed: {card.get("name")} -> {complete}')
67
68 elif action_type == 'commentCard':
69 text = data.get('text', '')
70 member = action.get('memberCreator', {}).get('fullName', 'Unknown')
71 print(f'Comment by {member}: {text[:100]}')
72
73 return 'OK', 200
74
75@app.route('/register-webhook', methods=['POST'])
76def create_webhook():
77 """Endpoint to register a new Trello webhook."""
78 data = request.json
79 board_id = data.get('boardId')
80 callback_url = data.get('callbackUrl')
81
82 if not board_id or not callback_url:
83 return jsonify({'error': 'boardId and callbackUrl required'}), 400
84
85 webhook = register_webhook(board_id, callback_url)
86 return jsonify({'webhook': webhook})
87
88if __name__ == '__main__':
89 app.run(host='0.0.0.0', port=3000)

Pro tip: Trello only sends one webhook per model (board, list, or card). To monitor multiple boards, you need to register a separate webhook for each board ID. The HEAD endpoint handler is required β€” Trello will reject webhook registration if the URL does not respond to HEAD with 200.

Expected result: After calling /register-webhook with your board ID and deployment URL, Trello delivers events to /trello-webhook whenever cards are created or moved on that board.

Common use cases

Automated Card Creation from Form Submissions

When a user submits a contact form or support request on your website, automatically create a Trello card in the correct list with the user's details, priority label, and due date. The card appears in your team's Trello board instantly without any manual data entry.

Replit Prompt

Build an Express server with a /submit-task POST endpoint. When called with title, description, priority, and email fields, create a new Trello card in the specified list ID, add a colored label based on priority, set a due date, and include the email in the card description. Store TRELLO_API_KEY and TRELLO_TOKEN in environment variables.

Copy this prompt to try it in Replit

Cross-System Status Sync

Build a webhook bridge that moves Trello cards between lists automatically when events happen in other systems β€” for example, move a card from 'In Progress' to 'Done' when a GitHub PR is merged, or move it back to 'Review' when a new comment is added.

Replit Prompt

Create a Flask server that receives GitHub webhook events. When a PR is merged, it should look up the matching Trello card by matching the PR title or branch name, then use the Trello API to move the card to the 'Done' list ID on the specified board. Return 200 for all recognized events.

Copy this prompt to try it in Replit

Project Progress Dashboard

Build a read-only dashboard that queries your Trello boards and aggregates card counts by list, shows overdue cards, and calculates throughput β€” all without Trello Power-Ups or paid add-ons, just your own Replit backend serving the data.

Replit Prompt

Create an Express API with a /board-stats/:boardId endpoint that fetches all lists and cards from a Trello board, counts cards per list, identifies cards with due dates in the past that are not marked complete, and returns the aggregated stats as JSON for a dashboard frontend.

Copy this prompt to try it in Replit

Troubleshooting

API returns '401 Unauthorized' or 'invalid token'

Cause: The most common causes are: the API Key or Token was copied with extra whitespace or newline characters, the Token was revoked in Trello Settings, or you are using an expired time-limited Token (if you generated a Token with expiration=1day).

Solution: Verify your credentials by testing directly in the Replit Shell: curl 'https://api.trello.com/1/members/me?key=YOUR_KEY&token=YOUR_TOKEN'. A valid response returns your profile JSON. If it fails, regenerate your Token at trello.com/power-ups/admin and update the TRELLO_TOKEN secret in Replit. Check that you authorized a 'never' expiration Token.

Webhook registration returns 'callbackURL is not valid' or 403 error

Cause: Trello validates the callback URL when you register a webhook by sending a HEAD request to it. If the URL is not accessible (development URL, not yet deployed), returns a non-200 status, or does not exist, the registration will fail.

Solution: Deploy your Replit app first using Autoscale deployment to get a stable URL. Ensure your webhook handler includes a route that responds to HEAD requests with 200. Test the URL manually in a browser or with curl before registering it with Trello.

typescript
1// Express β€” handle Trello's HEAD verification request
2app.head('/trello-webhook', (req, res) => res.sendStatus(200));
3app.post('/trello-webhook', (req, res) => {
4 // handle event...
5 res.sendStatus(200);
6});

createCard returns 'invalid id' for the list ID

Cause: The list ID (idList) provided in the card creation request does not exist or is malformed. Trello list IDs are 24-character hexadecimal strings. A common mistake is using the list name instead of the ID, or copying an ID with extra characters.

Solution: Find valid list IDs by calling GET /boards/{boardId}/lists with your credentials and checking the 'id' field on each list object. List IDs look like 5f3d8e1a2b4c6d8e0a2b4c6d. You can also find them by adding .json to your board URL and searching for the list name in the JSON response.

typescript
1// Find list IDs for a board
2const lists = await trelloGet(`/boards/${boardId}/lists?fields=id,name`);
3console.log(lists.map(l => ({ id: l.id, name: l.name })));

Webhook events stop arriving after a period of time

Cause: Trello automatically deletes webhooks that return non-200 responses for too many consecutive deliveries (typically after 50 consecutive failures). If your Replit app was redeploying or experiencing downtime, webhook deliveries may have failed repeatedly.

Solution: Check your webhook status by calling GET /tokens/{token}/webhooks. If the webhook is missing, re-register it. To prevent this, use a Reserved VM deployment for critical webhook endpoints that need guaranteed uptime, or implement proper error handling in your webhook handler to always return 200 (even if internal processing fails).

typescript
1// Always return 200, handle errors internally
2app.post('/trello-webhook', async (req, res) => {
3 res.sendStatus(200); // Acknowledge immediately
4 try {
5 await processWebhookEvent(req.body);
6 } catch (err) {
7 console.error('Webhook processing error:', err.message);
8 // Don't let errors cause non-200 responses to Trello
9 }
10});

Best practices

  • Always make Trello API calls from your Replit backend server, never from client-side JavaScript β€” the API Key and Token appear in request URLs, and exposing them in the browser allows anyone viewing your page source to access your Trello boards.
  • Store your TRELLO_API_KEY and TRELLO_TOKEN in Replit Secrets (lock icon in sidebar) and also consider storing frequently-used board and list IDs as secrets or environment variables to avoid hardcoding them in your codebase.
  • Use the ?fields= query parameter to request only the fields you need β€” by default Trello returns 30+ fields per card, but most use cases need only id, name, desc, and idList, which significantly reduces response size.
  • Always include a HEAD request handler on your webhook endpoint β€” Trello sends an HTTP HEAD request to validate the URL before registering a webhook, and the registration will fail if your endpoint does not respond with 200.
  • Deploy webhook receivers on Autoscale to ensure 24/7 availability β€” Trello will delete webhooks that receive too many consecutive failures, and the development URL is not available when your browser is closed.
  • Cache board structure (board ID, list IDs, label IDs) in your application to avoid fetching it on every API call β€” board structure rarely changes and these values are safe to store in Replit Secrets or a configuration object.
  • Implement idempotent card creation to prevent duplicate cards when your endpoint is called multiple times β€” check for an existing card with the same title before creating a new one, or use a unique identifier in the card description to deduplicate.

Alternatives

Frequently asked questions

How do I connect Replit to Trello?

Generate a Trello API Key at trello.com/power-ups/admin, then authorize a Token by clicking the Token link on the API Key page. Store both as TRELLO_API_KEY and TRELLO_TOKEN in Replit Secrets (lock icon in the sidebar). Access them in code as process.env.TRELLO_API_KEY (Node.js) or os.environ['TRELLO_API_KEY'] (Python), and append them as query parameters to all Trello API requests.

Does Replit work with Trello webhooks?

Yes, but your Replit app must be deployed to use webhooks β€” the development URL only works while your browser is open. Deploy with Autoscale to get a stable https://your-app.replit.app URL. Your webhook endpoint must also respond to HEAD requests with 200, which Trello uses to verify the URL when registering the webhook.

How do I find Trello list IDs and board IDs?

The quickest way is to add .json to your Trello board URL in the browser (e.g., trello.com/b/XXXX/my-board.json) and search for 'id' in the response. For list IDs, call GET https://api.trello.com/1/boards/{boardId}/lists?key=KEY&token=TOKEN and find the id field for each list. You can also use the Trello API Explorer at developer.atlassian.com/cloud/trello/rest/.

Can I use the Trello API for free?

Yes, the Trello REST API is free for all Trello account types. There is a rate limit of 300 requests per 10 seconds per API key and 100 requests per 10 seconds per token. For typical integration use cases (creating cards, reading boards, moving cards), these limits are more than sufficient. Free Trello accounts have limits on Power-Ups and attachments but not on API access.

How do I store Trello API credentials securely in Replit?

Open the Replit Secrets panel (lock icon πŸ”’ in the sidebar) and add TRELLO_API_KEY and TRELLO_TOKEN as separate secrets. Replit encrypts these with AES-256 and injects them as environment variables at runtime. Never paste them directly into your code β€” Replit's Secret Scanner monitors code files for API key patterns and will prompt you to move them to Secrets.

Why is my Trello webhook not receiving events?

The two most common reasons are: you registered the webhook with the development URL instead of the deployment URL, or your webhook endpoint does not respond to HEAD requests. Deploy your app using Autoscale deployment to get a stable URL, add a HEAD handler that returns 200, then re-register the webhook. You can verify your webhook status by calling GET /tokens/{token}/webhooks with your Trello credentials.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation β€” no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.