# Trello

- Tool: FlutterFlow
- Difficulty: Beginner
- Time required: 40 minutes
- Last updated: July 2026

## TL;DR

Connect FlutterFlow to Trello using a FlutterFlow API Call with URL-parameter authentication — not a header. Add key and token as API Group Variables so they auto-append to every request as ?key={apiKey}&token={userToken}. Chain GET /boards/{id}/lists then GET /lists/{id}/cards to build a kanban view, and route card-creation POST calls through a Firebase Cloud Function since the token appears in logged URLs.

## Build a Mobile Trello Kanban Viewer in FlutterFlow

Trello's visual board-and-card metaphor translates naturally to a mobile app — lists become vertical columns and cards become tappable items. FlutterFlow's horizontal Row of ListViews matches the kanban layout neatly. With Trello's REST API, you can replicate most of the core Trello experience: view boards, browse lists and their cards, check due dates and assignees, and add new cards.

Trello's API is available on all plans including the free tier. To access the API, you generate an API key from trello.com/power-ups/admin (which identifies your application) and a user token (which authorizes your account). Both go into every API call as URL query parameters: ?key=yourkey&token=yourtoken. There is no Authorization header — this is the single most important Trello-specific fact, and it trips up developers who expect Bearer or Basic auth patterns.

Trello returns flat JSON arrays without any envelope wrapper. A GET /lists/{id}/cards call returns directly: [ { "id": "...", "name": "...", ... }, ... ]. This is simpler to bind than Asana's data envelope or Jira's ADF fields — Trello is one of the more beginner-friendly REST APIs in the productivity space. The trade-off is that the token appears in every URL, which means it can show up in server logs and proxy access logs.

## Before you start

- A Trello account (free plan includes full API access)
- A Trello API key from trello.com/power-ups/admin → Power-Up Admin Portal → New → API Key
- A Trello user token generated from the API key page (click 'Token' link to authorize your account)
- The board ID for the board you want to display (visible in the Trello board URL after /b/)
- A Firebase project if you want to protect write operations (card creation, card moves) via Cloud Functions

## Step-by-step guide

### 1. Generate your Trello API key and user token

Go to trello.com/power-ups/admin in your browser. This is the Trello Power-Up Admin Portal. Click New to create a new integration entry. Give it a name like 'FlutterFlow App' and fill in your details. Once created, your API key will appear on the page — this is a permanent key tied to your Trello account.

Now generate a user token. On the same API key page, click the blue 'Token' link next to your API key. Trello will open an authorization page asking you to allow the integration. Click Allow. You'll be redirected to a page showing your token — copy it immediately.

The API key identifies your application. The user token authorizes your specific Trello account. Both are required in every API call. The user token grants read and write access to everything your account can access in Trello (by default), so treat it like a password.

Also find the board ID you want to display. Open any Trello board in a browser. The board ID is the short alphanumeric string in the URL after /b/ — for example, in https://trello.com/b/AbCdEf12/my-board, the board ID is AbCdEf12. You'll need this in a later step.

**Expected result:** You have your Trello API key, user token, and target board ID copied and ready to use.

### 2. Create the Trello API Group with URL-parameter auth

In FlutterFlow, click API Calls in the left navigation sidebar. Click + Add → Create API Group. Name the group Trello.

Set the Base URL to https://api.trello.com/1 — this is the base for all Trello REST API endpoints.

Here's the key difference from other tools: Trello authentication goes in URL query parameters, not in an Authorization header. To configure this in FlutterFlow, go to the Variables tab of the API Group (not the individual calls). Add two group-level variables:
- Variable 1: name key, type String, default value: YOUR_TRELLO_API_KEY
- Variable 2: name token, type String, default value: YOUR_TRELLO_USER_TOKEN

Now every child API Call you create inside this group will have access to these variables. You'll reference them in each endpoint URL as ?key={{key}}&token={{token}}.

Do NOT add an Authorization header. Trello rejects calls that use Bearer or Basic auth headers instead of URL parameters — if you add an Authorization header and omit the URL params, you'll get 401 Unauthorized errors regardless of credential validity.

Save the API Group. You're ready to add the first API call.

```
// API Group configuration reference
// Group name: Trello
// Base URL: https://api.trello.com/1
// Group-level Variables (appended to each child call's URL):
// key   → YOUR_TRELLO_API_KEY
// token → YOUR_TRELLO_USER_TOKEN
//
// IMPORTANT: No Authorization header!
// Auth goes in the URL as ?key={{key}}&token={{token}}
```

**Expected result:** A Trello API Group is saved with the base URL and two group-level variables (key, token) ready to be used in endpoint URLs.

### 3. Add GET /boards/{id}/lists and test the response

Inside the Trello API Group, click Add API Call. Name it GetBoardLists. Set the method to GET and the endpoint to /boards/{{boardId}}/lists?key={{key}}&token={{token}}&fields=name,id,pos,closed.

Add a call-level variable named boardId with type String and a default value of your board ID (the 8-character string from the board URL). The ?key={{key}}&token={{token}} in the endpoint URL references the group-level variables you set up in the previous step.

The fields parameter works like Asana's opt_fields — it limits which card/list fields come back. For the lists call, name, id, pos, and closed are all you need.

Go to the Response & Test tab. Click Test API Call. You should see a JSON array of list objects — Trello returns flat arrays without any envelope wrapper:
[
  { "id": "abc123", "name": "To Do", "pos": 16384, "closed": false },
  { "id": "def456", "name": "In Progress", "pos": 32768, "closed": false }
]

Click Generate from Response to create JSON Paths. Since there's no envelope, your paths will start with $[*] directly:
- $[*].id → list ID
- $[*].name → list name
- $[*].pos → position (for ordering)

This flat structure is much simpler than Asana or Jira. Trello's lack of an envelope is one of its beginner-friendly traits.

```
// GET /boards/{boardId}/lists response — flat array, no envelope
[
  {
    "id": "60abc1234def5678901234ab",
    "name": "To Do",
    "pos": 16384,
    "closed": false,
    "idBoard": "AbCdEf12"
  },
  {
    "id": "60abc1234def5678901234cd",
    "name": "In Progress",
    "pos": 32768,
    "closed": false,
    "idBoard": "AbCdEf12"
  },
  {
    "id": "60abc1234def5678901234ef",
    "name": "Done",
    "pos": 49152,
    "closed": false,
    "idBoard": "AbCdEf12"
  }
]

// JSON Paths (note: $[*] not $.data[*])
// $[*].id   → list ID (use this to fetch cards)
// $[*].name → list name (display as column header)
// $[*].pos  → position (sort columns by this value)
```

**Expected result:** GetBoardLists returns a flat JSON array of list objects. JSON Paths for id and name are generated. You can see your actual Trello lists in the Response tab.

### 4. Fetch cards per list and build the kanban layout

Add a second API Call inside the Trello group. Name it GetListCards. Method: GET. Endpoint: /lists/{{listId}}/cards?key={{key}}&token={{token}}&fields=name,desc,due,dueComplete,idMembers,idList,closed. Add a variable named listId.

Trello's card response is also a flat array — no envelope, simpler bindings than Asana:
[ { "id": "...", "name": "Fix login bug", "due": "2026-07-15T12:00:00.000Z", ... } ]

In your FlutterFlow board page, create a horizontal kanban layout. The structure is:
- Page → Column → ScrollView (horizontal=true) → Row → [for each list: Column with a Text header + ListView of cards]

To dynamically generate the list columns, use a ListView with Axis set to Horizontal (or a Row inside a SingleChildScrollView). Bind this to the GetBoardLists Backend Query. Inside, add a child Column for each list item:
- A Text widget bound to $[*].name (the list name as a column header)
- A nested ListView bound to GetListCards, passing the current list's $[*].id as the listId variable
- Inside the card ListView: a Card widget with Text bound to card $[*].name, and optionally a Text for $[*].due formatted as a date string

Note: the nested Backend Query pattern (a ListView inside a ListView) works in FlutterFlow but can be performance-intensive if you have many lists and many cards. Lazy-load cards only for the visible lists rather than all lists at once.

```
// GET /lists/{listId}/cards response — flat array, no envelope
[
  {
    "id": "card123abc",
    "name": "Fix login button on mobile",
    "desc": "The button isn't clickable below iOS 15",
    "due": "2026-07-15T12:00:00.000Z",
    "dueComplete": false,
    "idList": "60abc1234def5678901234ab",
    "idMembers": ["member123"],
    "closed": false
  },
  {
    "id": "card456def",
    "name": "Design onboarding screens",
    "desc": "",
    "due": null,
    "dueComplete": false,
    "idList": "60abc1234def5678901234ab",
    "idMembers": [],
    "closed": false
  }
]

// Key JSON Paths for cards
// $[*].id   → card ID (needed for PUT/DELETE)
// $[*].name → card title
// $[*].due  → due date ISO string (can be null)
// $[*].desc → description text
```

**Expected result:** GetListCards API Call returns cards for a given list. Your FlutterFlow page shows a horizontal scrolling board with list names as column headers and card names as items in each column.

### 5. Route card creation through a Firebase Cloud Function

Adding new cards to Trello (POST /cards) is a write operation. The user token you configured grants write access to all boards the account can see. Since the token appears in the URL of every Trello API call, it's visible in network logs, browser history, and proxy server access logs if included in a client-side POST.

For apps where this is a concern — any consumer-facing or externally accessible app — route card creation through a Firebase Cloud Function. The function holds the API key and token as server-side environment variables, accepts card data from the FlutterFlow app, calls Trello's POST /cards server-side, and returns the created card ID.

In FlutterFlow, create a separate API Group named TrelloProxy with the base URL of your Firebase Function (e.g., https://us-central1-your-project.cloudfunctions.net/createTrelloCard). Add a CreateCard POST call with a body accepting listId, name, desc, and due. No key or token parameters in this FlutterFlow call — the Cloud Function adds them server-side.

For the card-move action (PUT /cards/{id}?idList={newListId}), use the same pattern: send a request to a Cloud Function that performs the PUT with the token server-side.

Note Trello's rate limit: 300 requests per 10 seconds per API key, and 100 per 10 seconds per token. A kanban board loading all lists and cards can approach this limit if the board has many lists. Fetch lists once (store in App State), and lazy-load cards per list to keep requests low.

```
// Firebase Cloud Function: createTrelloCard/index.js
const functions = require('firebase-functions');
const fetch = require('node-fetch');

exports.createTrelloCard = functions.https.onRequest(async (req, res) => {
  res.set('Access-Control-Allow-Origin', '*');
  res.set('Access-Control-Allow-Methods', 'POST, OPTIONS');
  res.set('Access-Control-Allow-Headers', 'Content-Type');

  if (req.method === 'OPTIONS') {
    res.status(204).send('');
    return;
  }

  const TRELLO_KEY = process.env.TRELLO_API_KEY;
  const TRELLO_TOKEN = process.env.TRELLO_TOKEN;

  const { listId, name, desc, due } = req.body;

  // Build the URL with auth params server-side
  const url = new URL('https://api.trello.com/1/cards');
  url.searchParams.append('key', TRELLO_KEY);
  url.searchParams.append('token', TRELLO_TOKEN);
  url.searchParams.append('idList', listId);
  url.searchParams.append('name', name);
  if (desc) url.searchParams.append('desc', desc);
  if (due) url.searchParams.append('due', due);

  try {
    const response = await fetch(url.toString(), { method: 'POST' });
    const data = await response.json();
    res.status(response.status).json(data);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// Set Firebase env vars:
// firebase functions:config:set trello.api_key="KEY" trello.token="TOKEN"
```

**Expected result:** A Firebase Cloud Function handles card creation. New cards submitted from your FlutterFlow form appear in Trello with the Trello API key and token never exposed in the client-side code.

## Best practices

- Define key and token as API Group Variables, not individual call parameters — this lets you update credentials in one place and ensures they're consistently appended to every endpoint URL.
- Fetch list metadata once on page load and store in App State; avoid re-fetching lists every time the user scrolls back to the board.
- Add ?filter=open to the GET /lists endpoint to exclude archived lists from your kanban view automatically.
- Use the fields URL parameter on card calls (e.g., ?fields=name,desc,due,idMembers) to limit response payload size — omitting it returns dozens of card fields you likely don't need.
- Route all write operations (POST /cards, PUT /cards/{id}) through a Firebase Cloud Function so the token doesn't appear in browser network logs or URL history.
- Guard the due date binding with a Conditional Widget — cards without due dates return null for the due field, and binding null to a Text widget may cause display errors.
- Display a loading indicator while the nested list→cards queries run — on boards with many lists, the page can appear blank for 1-2 seconds while all card fetches complete.
- Add pull-to-refresh functionality (Flutter's RefreshIndicator) to let users manually reload the board rather than polling on a timer.

## Use cases

### Mobile kanban board viewer for a product team

Build a FlutterFlow app that displays a Trello board with its lists and cards in a horizontally scrolling layout. The app fetches all lists for a specified board ID, then fetches cards for each list, and arranges them in a Row where each column is a ListView of cards. Team members can view card names, due dates, and assigned members on the go.

Prompt example:

```
Show a horizontal kanban board from Trello with lists as columns and cards as items. Display each card's name, due date, and member count.
```

### Task intake app that creates Trello cards from a form

Build a simple form app where users submit a request (name, description, deadline) that creates a card in a designated Trello intake list. New card submissions go through a Cloud Function to protect the write-capable token. A confirmation screen shows the created card link. Useful for content request queues, bug reports, or customer intake forms.

Prompt example:

```
Let users fill out a form with title, description, and due date, then create a new card in a specific Trello list and show a success confirmation.
```

### Personal project tracker with card status updates

Build a personal productivity app that shows all boards the user's Trello account can access. Tapping a board shows its lists and cards. Tapping a card shows full card details including description, checklists, and comments. The user can move a card to a different list by tapping a 'Move to' action that sends a PUT request via a Cloud Function.

Prompt example:

```
Show all my Trello boards with their lists and cards. Let me tap a card to see its full details and move it to a different list.
```

## Troubleshooting

### 401 Unauthorized — credentials appear to be correct

Cause: The most common cause is adding an Authorization header instead of URL query parameters. Trello's API does not use Authorization headers — the key and token must be in the URL as query parameters (?key=...&token=...).

Solution: Remove any Authorization header from your API Group or API Call headers. Add key and token as group-level Variables instead, and reference them in every endpoint URL as ?key={{key}}&token={{token}}. Test with the full URL visible in the Response & Test tab to confirm the parameters are appended correctly.

### 429 Too Many Requests when loading the board

Cause: Loading all lists and immediately fetching cards for every list at once generates many parallel requests. Trello's rate limit is 300 requests per 10 seconds per API key — a board with 10 lists triggers 11 requests simultaneously, which can overwhelm the per-token limit (100/10s) if other calls are in flight.

Solution: Fetch list metadata once (store in App State), then load cards for lists only as the user scrolls to them. Alternatively, cache the first board fetch in App State and only refresh on explicit pull-to-refresh to reduce request frequency.

### Cards ListView is empty but GetListCards shows data in the Response tab

Cause: The listId variable being passed to GetListCards is empty or incorrect. This happens when the parent GetBoardLists ListView doesn't pass the current list item's ID to the child cards call.

Solution: In your FlutterFlow board page, check the Backend Query configuration for the nested cards ListView. Make sure the listId variable is set to 'From Widget' → the parent list item's JSON Path $[*].id (not a hardcoded value). Use the Response & Test tab with a specific listId to confirm the call returns cards when given the correct ID.

### XMLHttpRequest error on web build — board works on mobile

Cause: Browser CORS enforcement blocks direct calls to api.trello.com on published FlutterFlow web builds. Trello does include CORS headers for some origins, but custom domains may be blocked depending on their CORS configuration.

Solution: Route all Trello API calls through a Firebase Cloud Function that sets Access-Control-Allow-Origin: * headers. The FlutterFlow web app calls the Cloud Function URL instead of api.trello.com directly. This approach also moves the key and token to a safe server-side location.

## Frequently asked questions

### Why doesn't Trello use an Authorization header like other tools?

Trello's API was designed before Bearer token authentication became a widespread standard for REST APIs. Its key+token URL-parameter approach is a legacy design choice. The API has kept this pattern for backward compatibility. Functionally it works the same way — the key and token authenticate every request — but they appear in the URL rather than a header.

### Is it safe to put the Trello API key in App Constants in FlutterFlow?

The API key alone is not sensitive — it identifies your application but cannot authenticate requests without the token. The token is more sensitive because it grants write access to your Trello account. For read-only boards in internal tools, storing the token in App Constants is a pragmatic trade-off. For consumer-facing apps or any app where the board contains sensitive data, route write operations through a Cloud Function and consider read-only scoped tokens where possible.

### Can I display multiple boards in the same FlutterFlow app?

Yes. Use GET /members/me/boards?key={{key}}&token={{token}} to fetch all boards the account can access. Store the board list in App State and build a board-picker screen. When the user selects a board, store its ID in App State and use it as the boardId variable for all subsequent list and card calls. The board ID appears in each board's URL after /b/.

### Does this tutorial work for Trello Business Class or Premium accounts?

Yes. The REST API is identical across all Trello plans (Free, Standard, Premium, Enterprise). The API key and token generation process is the same, and all endpoints covered in this tutorial are available on every plan. Some Trello features like advanced checklists, dependencies, or timeline views may have additional API fields not covered here.

### How do I move a card from one list to another in FlutterFlow?

A card move is a PUT /cards/{cardId} request with the idList body parameter set to the destination list ID. In FlutterFlow, create a MoveCard API Call with method PUT, endpoint /cards/{{cardId}}?key={{key}}&token={{token}}, and a body of {"idList": "{{newListId}}"}. Add this as an action to a long-press or swipe gesture on each card widget. For write security, route this through a Cloud Function instead of calling Trello's API directly.

---

Source: https://www.rapidevelopers.com/flutterflow-integrations/trello
© RapidDev — https://www.rapidevelopers.com/flutterflow-integrations/trello
