Skip to main content
← All Guides
intermediate 20 min 300 XP

Build a Ticket Dashboard with Next.js

Build a simple ticket list dashboard using the cStar SDK and Next.js App Router. Covers server-side API calls, ticket listing, and status updates.

Prerequisites

  • Node.js 18+
  • A cStar account with a secret API key
  • Basic Next.js knowledge
1

Set up the project

Create a Next.js app and install the cStar SDK.

npx create-next-app@latest cstar-dashboard
cd cstar-dashboard
npm install @cstar.help/js
.env.local
CSTAR_SECRET_KEY=sk_live_your_key_here
CSTAR_TEAM_ID=your_team_id_here
2

Create the API client

Set up a shared cStar client instance. This runs server-side only — your secret key is never exposed to the browser.

lib/cstar.js
import { CStarClient } from '@cstar.help/js';

export const cstar = new CStarClient({
  apiKey: process.env.CSTAR_SECRET_KEY,
  teamId: process.env.CSTAR_TEAM_ID,
});
3

Build the ticket list page

Create a server component that fetches and displays tickets.

app/page.jsx
import { cstar } from '@/lib/cstar';

export default async function TicketDashboard() {
  const { data: tickets, pagination } = await cstar.tickets.list({
    status: 'open',
    pageSize: 20,
  });

  return (
    <main>
      <h1>Open Tickets ({pagination.total})</h1>
      <table>
        <thead>
          <tr>
            <th>Title</th>
            <th>Priority</th>
            <th>Customer</th>
            <th>Created</th>
          </tr>
        </thead>
        <tbody>
          {tickets.map((ticket) => (
            <tr key={ticket.id}>
              <td>{ticket.title}</td>
              <td>{ticket.priority}</td>
              <td>{ticket.customerName}</td>
              <td>{new Date(ticket.createdAt).toLocaleDateString()}</td>
            </tr>
          ))}
        </tbody>
      </table>
    </main>
  );
}
4

Add a status update action

Use a Server Action to close tickets from the dashboard.

app/actions.js
'use server';

import { cstar } from '@/lib/cstar';
import { revalidatePath } from 'next/cache';

export async function closeTicket(ticketId) {
  await cstar.tickets.update(ticketId, { status: 'closed' });
  revalidatePath('/');
}

What's Next?