Skip to main content

Overview

This recipe shows you how to pull all cards from a board and produce a summary report. The example groups cards by stage and calculates counts, but the same pattern works for any grouping or aggregation you need.

What you need

  • Your API key and board ID from Card Sources > API
  • Node.js 18 or later

Step 1: Fetch all cards from the board

async function getAllCards(boardId, apiKey) {
  const allCards = [];
  let page = 0;

  while (true) {
    const response = await fetch(
      `https://app.getaptly.com/api/aptlet/${boardId}?page=${page}`,
      { headers: { "x-token": apiKey } }
    );
    const cards = await response.json();
    if (cards.length === 0) break;
    allCards.push(...cards);
    page++;
  }

  return allCards;
}

Step 2: Group cards by stage

function groupByStage(cards) {
  return cards.reduce((acc, card) => {
    const stage = card.Stage || "No Stage";
    if (!acc[stage]) acc[stage] = [];
    acc[stage].push(card);
    return acc;
  }, {});
}

Step 3: Generate the report

async function runReport(boardId, apiKey) {
  const cards = await getAllCards(boardId, apiKey);
  const grouped = groupByStage(cards);

  console.log(`\n===== Board Report =====`);
  console.log(`Total cards: ${cards.length}`);
  console.log(`Generated: ${new Date().toLocaleString()}\n`);

  Object.entries(grouped)
    .sort((a, b) => b[1].length - a[1].length)
    .forEach(([stage, items]) => {
      console.log(`${stage}: ${items.length} cards`);
    });
}

runReport("YOUR_BOARD_ID", "YOUR_API_KEY");
Example output:
===== Board Report =====
Total cards: 143
Generated: 2/27/2026, 9:00:00 AM

Active: 61 cards
New Lead: 34 cards
In Progress: 28 cards
Completed: 15 cards
On Hold: 5 cards

Step 4: Export to CSV

To share the report or open it in a spreadsheet, write the results to a CSV file.
import { writeFileSync } from "fs";

function exportToCSV(cards, filename) {
  if (cards.length === 0) return;

  const headers = Object.keys(cards[0]).join(",");
  const rows = cards.map((card) =>
    Object.values(card)
      .map((v) => `"${String(v ?? "").replace(/"/g, '""')}"`)
      .join(",")
  );

  writeFileSync(filename, [headers, ...rows].join("\n"));
  console.log(`Exported ${cards.length} cards to ${filename}`);
}

const cards = await getAllCards("YOUR_BOARD_ID", "YOUR_API_KEY");
exportToCSV(cards, "board-report.csv");

Variations

Count cards updated in the last 7 days
const sevenDaysAgo = Date.now() - 7 * 24 * 60 * 60 * 1000;
const recentCards = cards.filter(
  (card) => new Date(card.updatedAt).getTime() > sevenDaysAgo
);
console.log(`Cards updated in the last 7 days: ${recentCards.length}`);
Find cards missing a required field
const incomplete = cards.filter((card) => !card.Email);
console.log(`Cards missing an email address: ${incomplete.length}`);
incomplete.forEach((card) => console.log(` ${card.Name} (${card._id})`));

Next steps