Skip to content
Docs
About By Dawn Contact supportOpen By Dawn
  1. Work with tickets
  2. List and filter tickets

List and filter tickets

Use this to read a board: to send a weekly report, to mirror tickets into another tool, or to find the tickets to act on next. By the end you’ll have every open ticket in a project, newest first.

Before you start: any key will do, read only is enough. To pick the project, set SAW_PROJECT_ID to its ID. Without it, the recipe uses your organization’s first project.

Read down the steps. The code on the right follows along and highlights the lines each one explains.

  1. Every recipe starts this way, as the Quickstart explains.

    // 1. Exchange the API key for a short-lived access token. Every call after this goes to your
    // organization's URL with the token as a Bearer header.
    const exchange: Schemas['ApiKeyExchange'] = { apiKey };
    const { accessToken: token } = await call<Schemas['AccessTokenData']['data']>(`${ACCOUNTS_URL}/auth/token/api-key`, { method: 'POST', body: exchange });
    const api = `${WORKSPACE_URL}/orgs/${orgIdOf(token)}`;
  2. An API key always lists tickets one project at a time, so the recipe needs a project ID. GET /projects lists them if you need to look one up.

    // 2. Choose the project: SAW_PROJECT_ID if you set it, or else your organization's first one.
    const projectId = process.env.SAW_PROJECT_ID ?? (await call<Schemas['Project'][]>(`${api}/projects`, { token }))[0]?.id;
    if (!projectId) throw new Error('This organization has no projects yet.');
  3. A project can hold thousands of tickets, so GET /tickets answers with one page and a nextCursor. The recipe asks for open tickets, newest first, 50 to a page, and sends the cursor back until it comes back empty. A cursor is a bookmark for this exact query, so the recipe passes it on untouched, with the same filters.

    If the API says the recipe is going too fast (429), it waits as long as the Retry-After header says and tries once more. Pagination and rate limits explains both in full.

    // 3. Ask for open tickets a page at a time, newest first, and follow nextCursor to the end.
    let cursor: string | null | undefined;
    let listed = 0;
    do {
    // URLSearchParams escapes each value; `nextCursor` is opaque and may hold + / = &.
    const query = new URLSearchParams({ projectId, open: 'true', sort: 'created', direction: 'desc', limit: '50' });
    if (cursor) query.set('cursor', cursor);
    const page = await getWithRetry<Schemas['TicketPage']>(`${api}/tickets?${query}`);
    if (listed === 0 && page.total !== undefined) console.log(`${page.total} open ticket(s):`);
    for (const ticket of page.items) {
    console.log(` ${ticket.identifier.padEnd(10)} ${ticket.priority.padEnd(11)} ${ticket.title}`);
    }
    listed += page.items.length;
    // `nextCursor` is null on the last page.
    cursor = page.nextCursor;
    } while (cursor);
    console.log(`Listed ${listed} ticket(s).`);

Run the TypeScript recipe from this page against your own organization. Your browser runs the same code, with your key standing in for SAW_API_KEY. See Try it in your browser.

Try it with your organization

How this works

Connect once and run this recipe live against the By Dawn API.

Your key stays in this tab and goes only to By Dawn. Use a read-only key in a test organization.

▶ Run list-tickets.tsThe same code CI runs, in your browser
Connect your organization above to run it.

Narrow the list in the request, not in your code: it’s faster, and it saves your rate limit. projectId is required with a key. Everything else is optional, and filters combine:

  • Where it sits: statusId, open (leave out the completed column) and includeArchived.
  • Planning: cycleId, epicId, milestoneId, releaseId and parentTicketId. For cycleId, epicId and parentTicketId, none means “not in any”. See Group work into epics for the epic IDs a project has.
  • People: assigneeId, and teamId for the team that owns the ticket (none for the tickets no team owns). See Organize work by team.
  • Text: q searches the identifier, title and description.
  • Order: sort (manual, priority, created, updated or title) and direction.

To find the IDs, use GET /projects, /statuses?projectId=…, /cycles and /users. The API reference documents each one.